using System.Collections; 
 | 
using System.Collections.Generic; 
 | 
using UnityEngine; 
 | 
using UnityEngine.UI; 
 | 
using System; 
 | 
using Cysharp.Threading.Tasks; 
 | 
  
 | 
    [ExecuteAlways] 
 | 
    public class AdaptiveLayout : MonoBehaviour 
 | 
    { 
 | 
        [SerializeField] HorizonOrVertical m_HorizonOrVerticle; 
 | 
        [SerializeField] CanvasGroup m_CanvasGroup; 
 | 
        [SerializeField] List<AdaptiveElement> m_AdapElements; 
 | 
        [SerializeField] bool m_AutoIncludeChild=false; 
 | 
        [SerializeField] float m_LeastHeight = 0f; 
 | 
        [SerializeField] float m_LeastWidth = 0f; 
 | 
        [SerializeField] float m_MaxHeight = 0f; 
 | 
        [SerializeField] float m_MaxWidth = 0f; 
 | 
        [NonSerialized] RectTransform m_Rect; 
 | 
        public RectTransform rectTransform 
 | 
        { 
 | 
            get 
 | 
            { 
 | 
                if (m_Rect == null) 
 | 
                { 
 | 
                    m_Rect = GetComponent<RectTransform>(); 
 | 
                } 
 | 
                return m_Rect; 
 | 
            } 
 | 
        } 
 | 
        public float Size 
 | 
        { 
 | 
            get 
 | 
            { 
 | 
                return m_HorizonOrVerticle == HorizonOrVertical.Horizon ? rectTransform.sizeDelta.x : rectTransform.sizeDelta.y; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        public event Action adaptiveUpdateEvent; 
 | 
  
 | 
        private void OnEnable() 
 | 
        { 
 | 
            if (m_AdapElements == null) 
 | 
            { 
 | 
                enabled = false; 
 | 
                return; 
 | 
            } 
 | 
            if (m_CanvasGroup != null) 
 | 
            { 
 | 
                m_CanvasGroup.alpha = 0; 
 | 
                m_CanvasGroup.interactable = true; 
 | 
                Co_DelayShow(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        private void TrackerRect(RectTransform _rect) 
 | 
        { 
 | 
            var _pivot = _rect.pivot; 
 | 
            var _anchorMax = _rect.anchorMax; 
 | 
            var _anchorMin = _rect.anchorMin; 
 | 
            if (m_HorizonOrVerticle == HorizonOrVertical.Horizon) 
 | 
            { 
 | 
                _pivot.x = 0; _pivot.y = 0.5f; 
 | 
                _anchorMax.x = 0; _anchorMax.y = 0.5f; 
 | 
                _anchorMin.x = 0; _anchorMin.y = 0.5f; 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                _pivot.x = 0.5f; _pivot.y = 1f; 
 | 
                _anchorMax.x = 0.5f; _anchorMax.y = 1; 
 | 
                _anchorMin.x = 0.5f; _anchorMin.y = 1; 
 | 
            } 
 | 
            if (_rect.pivot != _pivot || _rect.anchorMax != _anchorMax || _rect.anchorMin != _anchorMin) 
 | 
            { 
 | 
                _rect.pivot = _pivot; 
 | 
                _rect.anchorMax = _anchorMax; 
 | 
                _rect.anchorMin = _anchorMin; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        private void CalculateLayout() 
 | 
        { 
 | 
            var _offset = 0.0f; 
 | 
            var _horizon = m_HorizonOrVerticle == HorizonOrVertical.Horizon; 
 | 
            for (int i = 0; i < m_AdapElements.Count; i++) 
 | 
            { 
 | 
                if (m_AdapElements[i].rect == null || !m_AdapElements[i].rect.gameObject.activeInHierarchy) 
 | 
                { 
 | 
                    continue; 
 | 
                } 
 | 
                _offset += _horizon ? m_AdapElements[i].padding.left : m_AdapElements[i].padding.top; 
 | 
                var _pos = m_AdapElements[i].rect.localPosition; 
 | 
                if (_horizon) 
 | 
                { 
 | 
                    _pos.x = _offset; 
 | 
                } 
 | 
                else 
 | 
                { 
 | 
                    _pos.y = -_offset; 
 | 
                } 
 | 
                if (m_AdapElements[i].rect.localPosition != _pos) 
 | 
                { 
 | 
                    m_AdapElements[i].rect.localPosition = _pos; 
 | 
                } 
 | 
                _offset += _horizon ? m_AdapElements[i].rect.sizeDelta.x : m_AdapElements[i].rect.sizeDelta.y; 
 | 
                _offset += _horizon ? m_AdapElements[i].padding.right : m_AdapElements[i].padding.bottom; 
 | 
            } 
 | 
            var _sizeDelta = rectTransform.sizeDelta; 
 | 
            if (_horizon) 
 | 
            { 
 | 
                if (m_LeastWidth > 1f) 
 | 
                { 
 | 
                    _offset = Mathf.Max(_offset, m_LeastWidth); 
 | 
                } 
 | 
                if (m_MaxWidth > 1f) 
 | 
                { 
 | 
                    _offset = Mathf.Min(_offset, m_MaxWidth); 
 | 
                } 
 | 
                _sizeDelta.x = _offset; 
 | 
            } 
 | 
            else 
 | 
            { 
 | 
                if (m_LeastHeight > 1f) 
 | 
                { 
 | 
                    _offset = Mathf.Max(_offset, m_LeastHeight); 
 | 
                } 
 | 
                if (m_MaxHeight > 1f) 
 | 
                { 
 | 
                    _offset = Mathf.Min(_offset, m_MaxHeight); 
 | 
                } 
 | 
                _sizeDelta.y = _offset; 
 | 
            } 
 | 
            if (rectTransform.sizeDelta != _sizeDelta) 
 | 
            { 
 | 
                rectTransform.sizeDelta = _sizeDelta; 
 | 
                if (adaptiveUpdateEvent != null) 
 | 
                { 
 | 
                    adaptiveUpdateEvent(); 
 | 
                } 
 | 
            } 
 | 
        } 
 | 
  
 | 
        private void LateUpdate() 
 | 
        { 
 | 
            if (m_AdapElements == null) 
 | 
            { 
 | 
                return; 
 | 
            } 
 | 
            TrackerRect(rectTransform); 
 | 
            for (int i = 0; i < m_AdapElements.Count; i++) 
 | 
            { 
 | 
                if (m_AdapElements[i].rect == null) 
 | 
                { 
 | 
                    continue; 
 | 
                } 
 | 
                TrackerRect(m_AdapElements[i].rect); 
 | 
            } 
 | 
            CalculateLayout(); 
 | 
        } 
 | 
  
 | 
        private void OnTransformChildrenChanged() 
 | 
        { 
 | 
            if (m_AutoIncludeChild) 
 | 
            { 
 | 
                AutoIncludeChild(); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        private void AutoIncludeChild() 
 | 
        { 
 | 
            var _index = 0; 
 | 
            foreach (Transform _child in transform) 
 | 
            { 
 | 
                if (m_AdapElements == null) 
 | 
                { 
 | 
                    m_AdapElements = new List<AdaptiveElement>(); 
 | 
                } 
 | 
                var _rect = m_AdapElements.Find((x) => 
 | 
                 { 
 | 
                     return x.rect == _child; 
 | 
                 }); 
 | 
                var _rectOffset= _child.GetComponent<AdaptiveRectOffset>(); 
 | 
                if (_rect == null) 
 | 
                { 
 | 
                    m_AdapElements.Insert(_index, new AdaptiveElement(_child as RectTransform, _rectOffset)); 
 | 
                } 
 | 
                _index++; 
 | 
            } 
 | 
            if (m_AdapElements != null) 
 | 
            { 
 | 
                m_AdapElements.RemoveAll((x) => 
 | 
                { 
 | 
                    return x.rect == null; 
 | 
                }); 
 | 
            } 
 | 
            LateUpdate(); 
 | 
        } 
 | 
  
 | 
        async UniTask Co_DelayShow() 
 | 
        { 
 | 
            await UniTask.Delay(100); 
 | 
            if (m_CanvasGroup != null) 
 | 
            { 
 | 
                m_CanvasGroup.alpha = 1; 
 | 
            } 
 | 
        } 
 | 
  
 | 
        public enum HorizonOrVertical 
 | 
        { 
 | 
            Horizon, 
 | 
            Vertical, 
 | 
        } 
 | 
        [Serializable] 
 | 
        public class AdaptiveElement 
 | 
        { 
 | 
            [SerializeField] RectTransform m_Rect; 
 | 
            public RectTransform rect 
 | 
            { 
 | 
                get 
 | 
                { 
 | 
                    return m_Rect; 
 | 
                } 
 | 
            } 
 | 
            [SerializeField] RectOffset m_Padding; 
 | 
            public RectOffset padding 
 | 
            { 
 | 
                get 
 | 
                { 
 | 
                    return m_Padding; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            public AdaptiveElement(RectTransform _rect, AdaptiveRectOffset _offset) 
 | 
            { 
 | 
                m_Rect = _rect; 
 | 
                m_Padding = _offset == null ? new RectOffset() : _offset.rectOffset; 
 | 
            } 
 | 
        } 
 | 
  
 | 
    } 
 |