Code/Controls.cs
using System;
using Sandbox;
using Sandbox.UI;

namespace Goo;

// Composed control factories (compose-list widgets). Stateless: each returns a
// Container subtree, following the Shapes/Skins idiom.
public static partial class Controls
{
    // Maps a cursor X (in the root's rendered pixel frame) to a snapped, clamped value.
    // Ratio-based (localX / width) so it is scale-invariant; engine UI scaling changes
    // the absolute pixels but not the ratio (engine-fact-mousepanelevent-rendered-frame).
    internal static float ValueAt(float localX, float width, float min, float max, float step)
    {
        if (width <= 0f || max <= min) return min;
        float norm = Math.Clamp(localX / width, 0f, 1f);
        float v = min + norm * (max - min);
        if (step > 0f) v = MathF.Round(v / step) * step;
        return Math.Clamp(v, min, max);
    }

    // Dev-diagnostic sink for the degenerate max<=min case (mirrors Skins.OnZeroBorder).
    public static Action<string>? OnDegenerateRange;

    static readonly Color TrackBg = new( 0.28f, 0.28f, 0.34f, 1f );
    static readonly Color FillBg  = new( 0.55f, 0.78f, 0.95f, 1f );
    static readonly Color ThumbBg = new( 0.95f, 0.96f, 1.00f, 1f );

    // Controlled, stateless horizontal slider: the caller owns value, updates it in onChanged, and re-renders. Press-to-jump + drag within the bar (no engine move-capture; engine-fact-sbox-ui-input-and-drag); key pins reconciler identity so the Active pointer survives per-move re-renders.
    public static Container Slider(
        float value, float min, float max, float step,
        Action<float> onChanged, string? key = null )
    {
        if ( max <= min )
            OnDegenerateRange?.Invoke( $"Goo.Controls.Slider: max ({max}) <= min ({min}); rendering an inert track." );

        float pct = (max > min ? Math.Clamp( (value - min) / (max - min), 0f, 1f ) : 0f) * 100f;

        void Set( MousePanelEvent e )
            => onChanged( ValueAt( e.LocalPosition.x, e.Target.Box.Rect.Size.x, min, max, step ) );

        return new Container
        {
            Key            = key,
            PointerEvents  = PointerEvents.All,
            Width          = Length.Percent( 100 ),
            Height         = 20f,
            FlexDirection  = FlexDirection.Column,
            JustifyContent = Justify.Center,
            OnMouseDown    = Set,                                   // press jumps to position
            OnMouseMove    = e => { if ( e.Target.HasActive ) Set( e ); }, // drag while pressed
            Children =
            {
                new Container
                {
                    Key             = "track",
                    PointerEvents   = PointerEvents.None,
                    Position        = PositionMode.Relative,        // positioned ancestor for fill/thumb
                    Width           = Length.Percent( 100 ),
                    Height          = 7f,
                    BorderRadius    = 4f,
                    BackgroundColor = TrackBg,
                    Children =
                    {
                        new Container
                        {
                            Key             = "fill",
                            PointerEvents   = PointerEvents.None,
                            Position        = PositionMode.Absolute,
                            Left            = 0f,
                            Height          = Length.Percent( 100 ),
                            Width           = Length.Percent( pct ),
                            BorderRadius    = 4f,
                            BackgroundColor = FillBg,
                        },
                        new Container
                        {
                            Key             = "thumb",
                            PointerEvents   = PointerEvents.None,
                            Position        = PositionMode.Absolute,
                            Left            = Length.Percent( pct ),
                            Top             = Length.Percent( 50 ),
                            Width           = 16f,
                            Height          = 16f,
                            BorderRadius    = Length.Percent( 50 ),
                            BackgroundColor = ThumbBg,
                            // Center the thumb on the (x = value, y = track-mid) point.
                            // Length.Percent returns Length?, never null here; ?? default unwraps
                            // it the same way Px.Of does (the codebase's nullable-Length idiom).
                            Transform       = PanelTransform.Translate( Length.Percent( -50 ) ?? default, Length.Percent( -50 ) ?? default ),
                        },
                    },
                },
            },
        };
    }
}