@using System @namespace Sandbox.UI @inherits BaseControl @attribute [CustomEditor( typeof(float), WithAllAttributes = [ typeof(RangeAttribute) ] )] @if ( ShowTextEntry ) {
}
@if (ShowRange) {
@Min.ToString( NumberFormat )
@Max.ToString( NumberFormat )
}
@if (this.HasActive) {
}
@code { [Parameter] public Action OnValueChanged { get; set; } /// /// The right side of the slider. /// [Parameter] public float Max { get; set; } = 100; /// /// The left side of the slider. /// [Parameter] public float Min { get; set; } = 0; /// /// 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 /// [Parameter] public float Step { get; set; } = 1.0f; /// /// Show the range values above the slider /// [Parameter] public bool ShowRange { get; set; } = false; /// /// When changing the value show the tooltip /// [Parameter] public bool ShowValueTooltip { get; set; } = true; /// /// When changing the value show the tooltip /// [Parameter] public bool ShowTextEntry { get; set; } = false; /// /// How to display numbers in this control /// [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(out var rangeAttribute)) { Min = rangeAttribute.Min; Max = rangeAttribute.Max; } if ( Property.TryGetAttribute( out var stepAttribute ) ) { Step = stepAttribute.Step; } } /// /// Convert a screen position to a value. The value is clamped, but not snapped. /// 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; } /// /// If we move the mouse while we're being pressed then set the value /// 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(); } /// /// On mouse press jump to that position /// 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; }