using System; using UnityEngine; namespace Amanotes.Core { public enum SizeBase { Width, Height, Min, Max, FitFill, } public enum PaddingMode { None, Fixed, [InspectorName("% of Width")] PercentW, [InspectorName("% of Height")] PercentH, [InspectorName("% of MinWH")] PercentMin, } [Serializable] public class ComputedRect { public string id; // ─── Size ─── public bool customSize; // false = original size (no transform) public bool keepRatio = true; public SizeBase sizeBase = SizeBase.Width; public float ratio = 1f; // w/h aspect ratio (when keepRatio) public float percent = 1f; // multiplier on base dimension public float fitFill; // 0=fit, 1=fill (only when sizeBase=FitFill) // When keepRatio=false: independent stretch public float percentX = 1f; public float percentY = 1f; // ─── Padding ─── public PaddingMode paddingMode; public Vector4 padding; // (top, right, bottom, left) // ─── Align ─── public bool applyAlign; // ─── Pivot ─── public bool customPivot; // false = default (0.5, 0.5) public float pivotX = 0.5f; public float pivotY = 0.5f; // X axis positioning public bool alignEnableX = true; public float alignX = 0.5f; public float selfAlignX; // fraction of self width public float offsetX; // fixed offset // Y axis positioning public bool alignEnableY = true; public float alignY = 0.5f; public float selfAlignY; // fraction of self height public float offsetY; // fixed offset // ─── Cached ─── [NonSerialized] public Rect cachedRect; public Rect Compute(Vector2 srcSize, Vector2 srcPivot) { // Step 1: Padding → available float availW = srcSize.x; float availH = srcSize.y; if (paddingMode != PaddingMode.None) { float scale = paddingMode switch { PaddingMode.Fixed => 1f, PaddingMode.PercentW => srcSize.x, PaddingMode.PercentH => srcSize.y, PaddingMode.PercentMin => Mathf.Min(srcSize.x, srcSize.y), _ => 1f, }; float padT = padding.x * scale; float padR = padding.y * scale; float padB = padding.z * scale; float padL = padding.w * scale; availW = Mathf.Max(0f, srcSize.x - padL - padR); availH = Mathf.Max(0f, srcSize.y - padT - padB); } // Step 2: Size float w, h; if (!customSize) { w = availW; h = availH; } else if (keepRatio) { if (sizeBase == SizeBase.FitFill) { // Fit/Fill: uniform scale of rect with aspect=ratio into available float aspect = ratio > 0f ? ratio : 1f; float slider = Mathf.Clamp01(fitFill); if (availW <= 0f || availH <= 0f) { w = 0f; h = 0f; } else { float availAspect = availW / availH; float fitW, fitH, fillW, fillH; if (aspect > availAspect) { fitW = availW; fitH = fitW / aspect; fillH = availH; fillW = fillH * aspect; } else { fitH = availH; fitW = fitH * aspect; fillW = availW; fillH = fillW / aspect; } w = Mathf.Lerp(fitW, fillW, slider) * percent; h = Mathf.Lerp(fitH, fillH, slider) * percent; } } else { float baseVal = sizeBase switch { SizeBase.Width => availW, SizeBase.Height => availH, SizeBase.Min => Mathf.Min(availW, availH), SizeBase.Max => Mathf.Max(availW, availH), _ => availW, }; float primary = baseVal * percent; if (ratio > 0f) { if (sizeBase == SizeBase.Height) { h = primary; w = h * ratio; // w = h × ratio (UI: "w = h ×") } else { w = primary; h = w * ratio; // h = w × ratio (UI: "h = w ×") } } else { w = primary; h = primary; } } } else { // Independent stretch w = availW * percentX; h = availH * percentY; } w = Mathf.Max(0f, w); h = Mathf.Max(0f, h); // Step 3: Position float px = customPivot ? pivotX : 0.5f; float py = customPivot ? pivotY : 0.5f; float posX = -w * px; float posY = -h * py; if (applyAlign) { if (alignEnableX) { posX = srcSize.x * alignX - w * px + w * selfAlignX + offsetX; posX -= srcSize.x * srcPivot.x; } if (alignEnableY) { posY = srcSize.y * alignY - h * py + h * selfAlignY + offsetY; posY -= srcSize.y * srcPivot.y; } } cachedRect = new Rect(posX, posY, w, h); return cachedRect; } } }