using System.Collections.Generic; using UnityEngine; namespace Amanotes.Core { partial class Widget2D { [SerializeField] internal List _targets2 = new List(); [System.NonSerialized] private bool _isRefreshing; internal void ApplyTargets2() { if (_targets2 == null || _targets2.Count == 0 || _isRefreshing) return; _isRefreshing = true; var wSize = (Vector2)_size; var wPivot = _size.pivot; var useZ = _size.useZ; for (int i = 0; i < _targets2.Count; i++) { var t = _targets2[i]; if (!t.enabled || t.target == null) continue; if (string.IsNullOrEmpty(t.rectId)) { // Original: resize using widget's raw size var sz = ComputeSize(wSize, t); if (sz.x > 0f || sz.y > 0f) ApplySize(t, sz, useZ, wPivot); } else { var cr = GetComputedRect(t.rectId); if (cr == null) continue; // Size: only if rect has customSize if (cr.customSize) { var sz = t.percent == Vector2.zero && t.delta == Vector2.zero ? cr.cachedRect.size : ComputeSize(cr.cachedRect.size, t); if (sz.x > 0f || sz.y > 0f) ApplySize(t, sz, useZ, wPivot); } // Position: only if rect has applyAlign if (cr.applyAlign) { var rect = cr.cachedRect; var pos = new Vector2( rect.x + rect.width * 0.5f + t.offset.x, rect.y + rect.height * 0.5f + t.offset.y); ApplyOffset(t.target, pos, useZ); } } } _isRefreshing = false; } private static Vector2 ComputeSize(Vector2 baseSize, WidgetTarget t) { var sz = new Vector2( baseSize.x * t.percent.x + t.delta.x, baseSize.y * t.percent.y + t.delta.y); return Swizzle(sz, t.swizzle); } private void ApplySize(WidgetTarget t, Vector2 sz, bool useZ, Vector2 pivot) { switch (t.mode) { case TargetMode.Stretch: ApplyStretch(t.target, sz, useZ, pivot, t.spriteApply); break; case TargetMode.Fit: ApplyUniform(t.target, sz, fit: true); break; case TargetMode.Fill: ApplyUniform(t.target, sz, fit: false); break; case TargetMode.ScaleTransform: ApplyScaleTransform(t.target, sz, useZ); break; } } // ─── Swizzle ────────────────────────────────────────────────────────── private static Vector2 Swizzle(Vector2 v, AxisSwizzle swizzle) { switch (swizzle) { case AxisSwizzle.XY: return v; case AxisSwizzle.YX: return new Vector2(v.y, v.x); case AxisSwizzle.XZ: return v; case AxisSwizzle.ZX: return new Vector2(v.y, v.x); case AxisSwizzle.YZ: return new Vector2(v.y, v.x); case AxisSwizzle.ZY: return v; default: return v; } } // ─── Stretch ────────────────────────────────────────────────────────── private static void ApplyStretch(Component target, Vector2 sz, bool useZ, Vector2 pivot, SpriteApplyMode spriteApply) { switch (target) { case Widget2D widget: widget.size = sz; break; case BoxCollider box: ApplyBoxCollider(box, sz, useZ, pivot); break; case SpriteRenderer sr: ApplySpriteStretch(sr, sz, useZ, spriteApply); break; default: if (target is RectTransform rt) rt.sizeDelta = sz; break; } } private static void ApplyBoxCollider(BoxCollider box, Vector2 sz, bool useZ, Vector2 pivot) { var s = box.transform.localScale; var sx = Mathf.Abs(s.x) > 1e-6f ? s.x : 1f; var sy = Mathf.Abs(s.y) > 1e-6f ? s.y : 1f; var sz2 = Mathf.Abs(s.z) > 1e-6f ? s.z : 1f; if (useZ) box.size = new Vector3(sz.x / sx, box.size.y, sz.y / sz2); else box.size = new Vector3(sz.x / sx, sz.y / sy, box.size.z); var off = new Vector2(sz.x * (0.5f - pivot.x), sz.y * (0.5f - pivot.y)); if (useZ) box.center = new Vector3(off.x, box.center.y, off.y); else box.center = new Vector3(off.x, off.y, box.center.z); } private static void ApplySpriteStretch(SpriteRenderer sr, Vector2 sz, bool useZ, SpriteApplyMode spriteApply) { if (sr.sprite != null) { switch (spriteApply) { case SpriteApplyMode.Size: sr.drawMode = SpriteDrawMode.Sliced; sr.size = sz; sr.transform.localScale = Vector3.one; break; case SpriteApplyMode.Scale: { var r = sr.sprite.rect; var ppu = sr.sprite.pixelsPerUnit; var intrinsic = new Vector2(r.width / ppu, r.height / ppu); if (intrinsic.x > 0f && intrinsic.y > 0f) sr.transform.localScale = new Vector3(sz.x / intrinsic.x, sz.y / intrinsic.y, 1f); break; } default: // Auto { if (sr.drawMode == SpriteDrawMode.Simple) { var r = sr.sprite.rect; var ppu = sr.sprite.pixelsPerUnit; var intrinsic = new Vector2(r.width / ppu, r.height / ppu); if (intrinsic.x > 0f && intrinsic.y > 0f) sr.transform.localScale = new Vector3(sz.x / intrinsic.x, sz.y / intrinsic.y, 1f); } else { sr.size = sz; } break; } } } else { sr.drawMode = SpriteDrawMode.Sliced; sr.size = sz; } if (useZ) sr.transform.localRotation = Quaternion.Euler(90f, 0f, 0f); } // ─── Fit / Fill ─────────────────────────────────────────────────────── private static void ApplyUniform(Component target, Vector2 available, bool fit) { if (target is Widget2D widget) { var widgetSize = widget.size; if (widgetSize.x <= 0f || widgetSize.y <= 0f) return; var rx = available.x / widgetSize.x; var ry = available.y / widgetSize.y; widget.transform.localScale = Vector3.one * (fit ? Mathf.Min(rx, ry) : Mathf.Max(rx, ry)); return; } var intrinsic = GetIntrinsicSize(target); if (intrinsic.x <= 0f || intrinsic.y <= 0f) return; var irx = available.x / intrinsic.x; var iry = available.y / intrinsic.y; target.transform.localScale = Vector3.one * (fit ? Mathf.Min(irx, iry) : Mathf.Max(irx, iry)); } private static Vector2 GetIntrinsicSize(Component target) { switch (target) { case SpriteRenderer sr when sr.sprite != null: { var r = sr.sprite.rect; var ppu = sr.sprite.pixelsPerUnit; return new Vector2(r.width / ppu, r.height / ppu); } case MeshRenderer mr: { var mf = mr.GetComponent(); if (mf != null && mf.sharedMesh != null) { var b = mf.sharedMesh.bounds.size; return b.y > 0.01f ? new Vector2(b.x, b.y) : new Vector2(b.x, b.z); } return Vector2.one; } default: if (target is RectTransform rt) return rt.sizeDelta; return Vector2.one; } } // ─── Scale Transform ────────────────────────────────────────────────── private static void ApplyScaleTransform(Component target, Vector2 available, bool useZ) { Vector2 targetSize = target is Widget2D w ? w.size : GetIntrinsicSize(target); if (targetSize.x <= 0f || targetSize.y <= 0f) return; var sx = available.x / targetSize.x; var sy = available.y / targetSize.y; var tr = target.transform; if (useZ) tr.localScale = new Vector3(sx, tr.localScale.y, sy); else tr.localScale = new Vector3(sx, sy, tr.localScale.z); } // ─── Offset ─────────────────────────────────────────────────────────── private static void ApplyOffset(Component target, Vector2 pos, bool useZ) { var tr = target.transform; var lp = tr.localPosition; lp.x = pos.x; if (useZ) lp.z = pos.y; else lp.y = pos.y; tr.localPosition = lp; } // ─── Public API ─────────────────────────────────────────────────────── public void AddTarget(WidgetTarget entry) { _targets2 ??= new List(); _targets2.Add(entry); } public bool RemoveTarget(WidgetTarget entry) { if (_targets2 == null || entry == null) return false; return _targets2.Remove(entry); } public WidgetTarget GetTarget(Component component) { if (_targets2 == null || component == null) return null; for (int i = 0; i < _targets2.Count; i++) if (_targets2[i].target == component) return _targets2[i]; return null; } public WidgetTarget GetTargetByGameObject(GameObject go) { if (_targets2 == null || go == null) return null; for (int i = 0; i < _targets2.Count; i++) { var t = _targets2[i]; if (t.target != null && t.target.gameObject == go) return t; } return null; } } }