A Blazor-style Razor UI component for selecting hair color in the character editor. It renders a color square, hue slider, and a color swatch/text, tracks hue to preserve it across gray/black values, and notifies a callback when color changes.
@using Sandbox
@using Sandbox.UI
@using System
@namespace CharacterEditor
@inherits Panel
<root>
<HairColorSquare Value=@Value Hue=@Hue OnValueChanged=@Pick />
<div class="shapelabel"><span>Hue</span><span>@MathF.Round(Hue)°</span></div>
<div class="hue-track"><SliderControl class="shapeslider hair-hue" Value=@Hue OnValueChanged=@SetHue Min=@(0f) Max=@(360f) Step=@(1f) ShowTextEntry=@false /></div>
<div class="hair-color-value"><div class="colorswatch" style=@($"background-color: rgb({Byte(Value.r)},{Byte(Value.g)},{Byte(Value.b)});")></div><span>@($"#{Byte(Value.r):X2}{Byte(Value.g):X2}{Byte(Value.b):X2}")</span></div>
</root>
@code {
public Color Value { get; set; }
public Action<Color> OnValueChanged { get; set; }
float Hue;
Color LastColor;
bool Initialized;
static int Byte(float value) => (int)MathF.Round(Math.Clamp(value, 0, 1) * 255);
protected override void OnParametersSet()
{
if (!Initialized || Value != LastColor)
{
var hsv = Value.ToHsv();
// Keep the selected hue when passing through gray or black.
if (!Initialized || (hsv.Saturation > .001f && hsv.Value > .001f)) Hue = hsv.Hue;
LastColor = Value;
Initialized = true;
}
}
void Pick(Color color) { LastColor = Value = color; OnValueChanged?.Invoke(color); StateHasChanged(); }
void SetHue(float hue) { Hue = hue; var hsv = Value.ToHsv(); Pick(new ColorHsv(Hue, hsv.Saturation, hsv.Value, 1).ToColor()); }
protected override int BuildHash() => HashCode.Combine(Value, Hue);
}