using System.Numerics; namespace AcDream.App.UI; /// /// A horizontal vital bar (retail HP/Stamina/Mana style): a background rect, a /// partial-width solid fill, and an optional centered "current/max" numeric /// overlay. returns 0..1 (null = no data → empty bar); /// returns the overlay text (null = no number). /// /// /// Solid-color fill + debug font for Spec 1. The retail gradient bar sprite /// (glassy center highlight) and the retail dat font are a later polish pass — /// retail's vitals are bars exactly like this, just sprited. /// /// public sealed class UiMeter : UiElement { /// Fill fraction provider; a null result draws an empty bar. public Func Fill { get; set; } = () => 0f; /// Centered overlay text provider (e.g. "291/291"); null = none. public Func Label { get; set; } = () => null; public Vector4 BarColor { get; set; } = new(1f, 0f, 0f, 1f); public Vector4 BgColor { get; set; } = new(0f, 0f, 0f, 0.5f); public Vector4 LabelColor { get; set; } = new(1f, 1f, 1f, 1f); public UiMeter() { ClickThrough = true; } /// Clamp to [0,1] and return the fill rect /// (local px) for a bar of x . public static (float x, float y, float w, float h) ComputeFillRect( float pct, float w, float h) { if (pct < 0f) pct = 0f; if (pct > 1f) pct = 1f; return (0f, 0f, w * pct, h); } protected override void OnDraw(UiRenderContext ctx) { ctx.DrawRect(0, 0, Width, Height, BgColor); float? pct = Fill(); if (pct is float p) { var (fx, fy, fw, fh) = ComputeFillRect(p, Width, Height); if (fw > 0f) ctx.DrawRect(fx, fy, fw, fh, BarColor); } string? label = Label(); if (!string.IsNullOrEmpty(label) && ctx.DefaultFont is { } font) { float tw = font.MeasureWidth(label); float tx = (Width - tw) * 0.5f; float ty = (Height - font.LineHeight) * 0.5f; ctx.DrawString(label, tx, ty, LabelColor); } } }