using System.Numerics;
namespace AcDream.App.UI;
///
/// A whose background is the retail 8-piece window bevel
/// (): 4 corners + 4 edges around a tiled
/// center fill. Retires the flat translucent rect (divergence row TS-30).
/// Sprites resolve to (GL handle, width, height) via an injected delegate so
/// the widget is testable without GL. In production:
/// id => { var t = cache.GetOrUploadRenderSurface(id, out var w, out var h); return (t, w, h); }.
///
public sealed class UiNineSlicePanel : UiPanel
{
/// A placed chrome piece: destination rect in local pixel space.
public readonly record struct Rect(float X, float Y, float W, float H);
/// The nine destination rects for an 8-piece border + center.
public readonly record struct FrameRects(
Rect Center, Rect Top, Rect Bottom, Rect Left, Rect Right,
Rect TL, Rect TR, Rect BL, Rect BR);
private readonly System.Func _resolve;
public UiNineSlicePanel(System.Func resolve)
{
_resolve = resolve;
BackgroundColor = Vector4.Zero; // suppress the base flat-rect fill
BorderColor = Vector4.Zero;
}
///
/// Destination rects (local px) for a frame of (,
/// ) with border thickness :
/// b×b corners, top/bottom edges spanning the interior width at height b,
/// left/right edges spanning the interior height at width b, center fills
/// the interior.
///
public static FrameRects ComputeFrameRects(float w, float h, int b)
{
float innerW = w - 2 * b;
float innerH = h - 2 * b;
return new FrameRects(
Center: new Rect(b, b, innerW, innerH),
Top: new Rect(b, 0, innerW, b),
Bottom: new Rect(b, h - b, innerW, b),
Left: new Rect(0, b, b, innerH),
Right: new Rect(w - b, b, b, innerH),
TL: new Rect(0, 0, b, b),
TR: new Rect(w - b, 0, b, b),
BL: new Rect(0, h - b, b, b),
BR: new Rect(w - b, h - b, b, b));
}
protected override void OnDraw(UiRenderContext ctx)
{
var r = ComputeFrameRects(Width, Height, RetailChromeSprites.Border);
// center + edges tile (UV repeat); corners stretch 1:1.
DrawTiled(ctx, RetailChromeSprites.CenterFill, r.Center);
DrawTiled(ctx, RetailChromeSprites.TopEdge, r.Top);
DrawTiled(ctx, RetailChromeSprites.BottomEdge, r.Bottom);
DrawTiled(ctx, RetailChromeSprites.LeftEdge, r.Left);
DrawTiled(ctx, RetailChromeSprites.RightEdge, r.Right);
DrawStretched(ctx, RetailChromeSprites.CornerTL, r.TL);
DrawStretched(ctx, RetailChromeSprites.CornerTR, r.TR);
DrawStretched(ctx, RetailChromeSprites.CornerBL, r.BL);
DrawStretched(ctx, RetailChromeSprites.CornerBR, r.BR);
}
private void DrawTiled(UiRenderContext ctx, uint id, Rect d)
{
if (d.W <= 0 || d.H <= 0) return;
var (tex, tw, th) = _resolve(id);
if (tex == 0 || tw == 0 || th == 0) return;
ctx.DrawSprite(tex, d.X, d.Y, d.W, d.H, 0, 0, d.W / tw, d.H / th, Vector4.One);
}
private void DrawStretched(UiRenderContext ctx, uint id, Rect d)
{
if (d.W <= 0 || d.H <= 0) return;
var (tex, _, _) = _resolve(id);
if (tex == 0) return;
ctx.DrawSprite(tex, d.X, d.Y, d.W, d.H, 0, 0, 1, 1, Vector4.One);
}
}