| | 1 | | using DCL.Components; |
| | 2 | | using DCL.Helpers; |
| | 3 | | using System.Linq; |
| | 4 | | using UnityEngine; |
| | 5 | | using UnityEngine.UI; |
| | 6 | |
|
| | 7 | | public class UISizeFitter : MonoBehaviour |
| | 8 | | { |
| | 9 | | public static bool VERBOSE = false; |
| 69 | 10 | | public bool adjustWidth = true; |
| 69 | 11 | | public bool adjustHeight = true; |
| | 12 | |
|
| | 13 | | RectTransform canvasChildHookRT; |
| | 14 | |
|
| 326 | 15 | | public void Refresh() { FitSizeToChildren(adjustWidth, adjustHeight); } |
| | 16 | |
|
| | 17 | | void EnsureCanvasChildHookRectTransform() |
| | 18 | | { |
| 163 | 19 | | if (canvasChildHookRT == null) |
| | 20 | | { |
| 41 | 21 | | Canvas canvas = GetComponentInParent<Canvas>(); |
| 41 | 22 | | if (canvas) |
| 41 | 23 | | canvasChildHookRT = canvas.GetComponent<RectTransform>(); |
| | 24 | | else |
| 0 | 25 | | canvasChildHookRT = GetComponentInParent<RectTransform>(); |
| | 26 | | } |
| 122 | 27 | | } |
| | 28 | |
|
| | 29 | | public void FitSizeToChildren(bool adjustWidth = true, bool adjustHeight = true) |
| | 30 | | { |
| 163 | 31 | | UIReferencesContainer[] containers = GetComponentsInChildren<UIReferencesContainer>(); |
| | 32 | |
|
| 163 | 33 | | EnsureCanvasChildHookRectTransform(); |
| | 34 | |
|
| 163 | 35 | | RectTransform rt = transform as RectTransform; |
| | 36 | |
|
| 163 | 37 | | if (rt == null || canvasChildHookRT == null || containers == null || containers.Length == 0) |
| | 38 | | { |
| 101 | 39 | | return; |
| | 40 | | } |
| | 41 | |
|
| 62 | 42 | | Rect finalRect = new Rect(); |
| 62 | 43 | | finalRect.xMax = float.MinValue; |
| 62 | 44 | | finalRect.yMax = float.MinValue; |
| 62 | 45 | | finalRect.xMin = float.MaxValue; |
| 62 | 46 | | finalRect.yMin = float.MaxValue; |
| | 47 | |
|
| 62 | 48 | | Vector3[] corners = new Vector3[4]; |
| | 49 | |
|
| 62 | 50 | | Vector3 center = Vector3.zero; |
| | 51 | |
|
| 62 | 52 | | Transform[] children = transform.Cast<Transform>().ToArray(); |
| | 53 | |
|
| 292 | 54 | | for (int i = 0; i < children.Length; i++) |
| | 55 | | { |
| | 56 | | //NOTE(Brian): We need to remove the children because we are going to try and resize the father without alte |
| | 57 | | // their positions--we are going to re-add them later. Note that i'm setting the parent to canva |
| | 58 | | // this is because worldPositionStays parameter isn't working with rotated/scaled canvases, if I |
| | 59 | | // current canvas, this is solved. |
| 84 | 60 | | children[i].SetParent(canvasChildHookRT, true); |
| | 61 | | } |
| | 62 | |
|
| 508 | 63 | | foreach (UIReferencesContainer rc in containers) |
| | 64 | | { |
| 192 | 65 | | RectTransform r = rc.childHookRectTransform; |
| | 66 | |
|
| 192 | 67 | | if (r == transform) |
| | 68 | | { |
| | 69 | | continue; |
| | 70 | | } |
| | 71 | |
|
| 150 | 72 | | if (VERBOSE) |
| | 73 | | { |
| 0 | 74 | | Debug.Log($"..... container... {r.name} ... w = {r.sizeDelta.x} h = {r.sizeDelta.y}", rc.gameObject); |
| | 75 | | } |
| | 76 | |
|
| 150 | 77 | | r.GetWorldCorners(corners); |
| | 78 | |
|
| | 79 | | //NOTE(Brian): We want the coords in canvas space to solve CanvasScaler issues and world canvas arbitrary tr |
| 150 | 80 | | corners[0] = canvasChildHookRT.InverseTransformPoint(corners[0]); |
| 150 | 81 | | corners[1] = canvasChildHookRT.InverseTransformPoint(corners[1]); |
| 150 | 82 | | corners[2] = canvasChildHookRT.InverseTransformPoint(corners[2]); |
| 150 | 83 | | corners[3] = canvasChildHookRT.InverseTransformPoint(corners[3]); |
| | 84 | |
|
| | 85 | | //TODO(Brian): This'll look cleaner with a Bounds.EncapsulateBounds solution. |
| 1500 | 86 | | for (int i = 0; i < corners.Length; i++) |
| | 87 | | { |
| 600 | 88 | | if (corners[i].x < finalRect.xMin) |
| | 89 | | { |
| 83 | 90 | | finalRect.xMin = corners[i].x; |
| | 91 | | } |
| | 92 | |
|
| 600 | 93 | | if (corners[i].x > finalRect.xMax) |
| | 94 | | { |
| 176 | 95 | | finalRect.xMax = corners[i].x; |
| | 96 | | } |
| | 97 | |
|
| 600 | 98 | | if (corners[i].y < finalRect.yMin) |
| | 99 | | { |
| 90 | 100 | | finalRect.yMin = corners[i].y; |
| | 101 | | } |
| | 102 | |
|
| 600 | 103 | | if (corners[i].y > finalRect.yMax) |
| | 104 | | { |
| 132 | 105 | | finalRect.yMax = corners[i].y; |
| | 106 | | } |
| | 107 | | } |
| | 108 | | } |
| | 109 | |
|
| 62 | 110 | | if (!adjustWidth) |
| | 111 | | { |
| 0 | 112 | | finalRect.width = rt.sizeDelta.x; |
| | 113 | | } |
| | 114 | |
|
| 62 | 115 | | if (!adjustHeight) |
| | 116 | | { |
| 0 | 117 | | finalRect.height = rt.sizeDelta.y; |
| | 118 | | } |
| | 119 | |
|
| 62 | 120 | | if (VERBOSE) |
| | 121 | | { |
| 0 | 122 | | Debug.Log($".....end! final rect... w = {finalRect.width} h = {finalRect.height}"); |
| | 123 | | } |
| | 124 | |
|
| | 125 | | //NOTE(Brian): In this last step, we need to transform from canvas space to world space. |
| | 126 | | // We need to use "position" because assumes its pivot in the lower right corner of the rect in worl |
| | 127 | | // This is exactly what we are looking for as we want an anchor agnostic solution. |
| 62 | 128 | | rt.position = canvasChildHookRT.TransformPoint(finalRect.min + (finalRect.size * rt.pivot)); |
| 62 | 129 | | rt.sizeDelta = new Vector2(finalRect.width, finalRect.height); |
| | 130 | |
|
| 292 | 131 | | for (int i = 0; i < children.Length; i++) |
| | 132 | | { |
| 84 | 133 | | children[i].SetParent(transform, true); |
| | 134 | | } |
| 62 | 135 | | } |
| | 136 | |
|
| | 137 | | void RefreshRecursively_Node(UISizeFitter fitter) |
| | 138 | | { |
| 163 | 139 | | fitter.Refresh(); |
| | 140 | |
|
| 163 | 141 | | LayoutGroup p = fitter.GetComponentInParent<LayoutGroup>(); |
| | 142 | |
|
| 163 | 143 | | if (p != null) |
| | 144 | | { |
| 163 | 145 | | Utils.ForceRebuildLayoutImmediate(p.transform as RectTransform); |
| | 146 | | } |
| 163 | 147 | | } |
| | 148 | |
|
| 188 | 149 | | public void RefreshRecursively(Transform startTransform = null) { Utils.InverseTransformChildTraversal<UISizeFitter> |
| | 150 | |
|
| | 151 | | #if UNITY_EDITOR |
| 132 | 152 | | private void Awake() { forceRefresh = false; } |
| | 153 | |
|
| | 154 | | //NOTE(Brian): Only used for debugging |
| | 155 | | public bool forceRefresh = false; |
| | 156 | |
|
| | 157 | | public void Update() |
| | 158 | | { |
| 1009 | 159 | | if (forceRefresh) |
| | 160 | | { |
| 0 | 161 | | RefreshRecursively(); |
| 0 | 162 | | forceRefresh = false; |
| | 163 | | } |
| 1009 | 164 | | } |
| | 165 | | #endif |
| | 166 | | } |