protected virtual void GetChildSizes(IFastLayoutFeedback child, int axis, bool controlSize, bool childForceExpand,
                                             out float min, out float preferred, out float flexible)
        {
            if (!controlSize)
            {
                min       = axis == 0 ? child.cachedRectWidth : child.cachedRectHeight;
                preferred = min;
                flexible  = 0;
            }
            else
            {
                min       = axis == 0 ? child.cachedMinWidth : child.cachedMinHeight;
                preferred = axis == 0 ? child.cachedPreferredWidth : child.cachedPreferredHeight;
                flexible  = axis == 0 ? child.cachedFlexibleWidth : child.cachedFlexibleHeight;
            }

            //Prevent expand when child control size
            if (childForceExpand && (m_ForceExpandMode == ForceExpandMode.Inflate || !controlSize))
            {
                flexible = Mathf.Max(flexible, 1);
            }

            //Prevent negative values on return
            flexible = Mathf.Max(flexible, 0);
        }
        /// <summary>
        /// Calculate the layout element properties for this layout element along the given axis.
        /// </summary>
        /// <param name="axis">The axis to calculate for. 0 is horizontal and 1 is vertical.</param>
        /// <param name="isVertical">Is this group a vertical group?</param>
        protected virtual void CalcAlongAxis(int axis, bool isVertical)
        {
            float combinedPadding      = (axis == 0 ? padding.horizontal : padding.vertical);
            bool  controlSize          = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight);
            bool  useScale             = (axis == 0 ? m_ChildScaleWidth : m_ChildScaleHeight);
            bool  childForceExpandSize = (axis == 0 ? m_ChildForceExpandWidth : m_ChildForceExpandHeight);

            float totalMin       = combinedPadding;
            float totalPreferred = combinedPadding;
            float totalFlexible  = 0;

            bool alongOtherAxis = (isVertical ^ (axis == 1));

            for (int i = 0; i < children.Count; i++)
            {
                IFastLayoutFeedback child = children[i];

                if (child == null)
                {
                    return;
                }

                float min, preferred, flexible;
                GetChildSizes(children[i], axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);

                if (useScale)
                {
                    float scaleFactor = child.rectTransform != null? child.rectTransform.localScale[axis] : 1.0f;
                    min       *= scaleFactor;
                    preferred *= scaleFactor;
                    flexible  *= scaleFactor;
                }

                if (alongOtherAxis)
                {
                    totalMin       = Mathf.Max(min + combinedPadding, totalMin);
                    totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred);
                    totalFlexible  = Mathf.Max(flexible, totalFlexible);
                }
                else
                {
                    totalMin       += min + spacing;
                    totalPreferred += preferred + spacing;

                    // Increment flexible size with element's flexible size.
                    totalFlexible += flexible;
                }
            }

            if (!alongOtherAxis && children.Count > 0)
            {
                totalMin       -= spacing;
                totalPreferred -= spacing;
            }
            totalPreferred = Mathf.Max(totalMin, totalPreferred);
            SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis);
        }
        public virtual void SetElementDirty(IFastLayoutFeedback driven, DrivenAxis dirtyAxis)
        {
            if (driven != null && (dirtyAxis.HasFlag(DrivenAxis.Ignore) || (dirtyAxis & childrenControlledAxis) != 0))
            {
                if (!isDirty)
                {
                    MarkLayoutForRebuild();
                }

                _dirtyChildren.Add(driven);
            }
        }
Beispiel #4
0
        public override void SetElementDirty(IFastLayoutFeedback driven, DrivenAxis dirtyAxis)
        {
            if (driven != null && (dirtyAxis.HasFlag(DrivenAxis.Ignore) || (dirtyAxis & childrenControlledAxis) != 0))
            {
                if (!isDirty)
                {
                    MarkLayoutForRebuild();
                }

                //Special case when added element will affect other elements size
                if (dirtyAxis.HasFlag(DrivenAxis.Ignore) &&
                    ((isVertical && m_TotalFlexibleSize.y > 0) ||
                     (!isVertical && m_TotalFlexibleSize.x > 0)))
                {
                    isAxisDirty = true;
                }

                _dirtyChildren.Add(driven);
            }
        }
        protected virtual void GetChildAnchors(IFastLayoutFeedback child, int axis, bool controlSize, bool childForceExpand, Vector2 defaultAnchor,
                                               out Vector2 minAnchor, out Vector2 maxAnchor)
        {
            minAnchor = child != null && child.rectTransform != null? child.rectTransform.anchorMin : defaultAnchor;
            maxAnchor = child != null && child.rectTransform != null ? child.rectTransform.anchorMax : defaultAnchor;

            var drivenAxis = axis == 0 ? DrivenAxis.Horizontal : DrivenAxis.Vertical;
            var expand     = !controlSize && (parentControlledAxis & drivenAxis) != 0;

            if (expand)
            {
                minAnchor[axis] = 0;
                maxAnchor[axis] = 1;
            }
            else
            {
                minAnchor[axis] = defaultAnchor[axis];
                maxAnchor[axis] = minAnchor[axis];
            }
        }
        /// <summary>
        /// Set the positions and sizes of the child layout elements for the given axis.
        /// </summary>
        /// <param name="axis">The axis to handle. 0 is horizontal and 1 is vertical.</param>
        /// <param name="isVertical">Is this group a vertical group?</param>
        protected virtual void SetChildrenAlongAxis(int axis, bool isVertical)
        {
            float size                 = rectTransform.rect.size[axis];
            bool  controlSize          = (axis == 0 ? m_ChildControlWidth : m_ChildControlHeight);
            bool  useScale             = (axis == 0 ? m_ChildScaleWidth : m_ChildScaleHeight);
            bool  childForceExpandSize = (axis == 0 ? m_ChildForceExpandWidth : m_ChildForceExpandHeight);
            float alignmentOnAxis      = GetAlignmentOnAxis(axis);

            var  isAxisDirty    = IsAxisDirty(isVertical);
            bool alongOtherAxis = (isVertical ^ (axis == 1));
            var  defaultAnchor  = GetDefaultChildAnchor();

            if (alongOtherAxis)
            {
                float innerSize = size - (axis == 0 ? padding.horizontal : padding.vertical);

                var elements = (isAxisDirty ? (ICollection <IFastLayoutFeedback>)children : _dirtyChildren);
                foreach (IFastLayoutFeedback child in elements)
                {
                    if (child.rectTransform == null || child.rectTransform.parent != this.transform)
                    {
                        return;
                    }

                    float min, preferred, flexible;
                    GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);

                    float scaleFactor = useScale && child.rectTransform != null? child.rectTransform.localScale[axis] : 1f;

                    Vector2 anchorMin, anchorMax;
                    GetChildAnchors(child, axis, controlSize, childForceExpandSize, defaultAnchor, out anchorMin, out anchorMax);

                    float requiredSpace = Mathf.Clamp(innerSize, min, flexible > 0 ? size : preferred);
                    float startOffset   = GetStartOffset(axis, requiredSpace * scaleFactor);
                    if (controlSize)
                    {
                        SetChildAlongAxisWithScale(child.rectTransform, axis, startOffset, requiredSpace, scaleFactor, anchorMin, anchorMax);
                    }
                    else
                    {
                        float offsetInCell = (requiredSpace - (axis == 0? child.cachedRectWidth : child.cachedRectHeight)) * alignmentOnAxis;
                        SetChildAlongAxisWithScale(child.rectTransform, axis, startOffset + offsetInCell, requiredSpace, scaleFactor, anchorMin, anchorMax);
                    }
                }
            }
            else
            {
                float pos = (axis == 0 ? padding.left : padding.top);
                float itemFlexibleMultiplier = 0;
                float surplusSpace           = size - GetTotalPreferredSize(axis);

                if (surplusSpace > 0)
                {
                    if (GetTotalFlexibleSize(axis) == 0)
                    {
                        pos = GetStartOffset(axis, GetTotalPreferredSize(axis) - (axis == 0 ? padding.horizontal : padding.vertical));
                    }
                    else if (GetTotalFlexibleSize(axis) > 0)
                    {
                        itemFlexibleMultiplier = surplusSpace / GetTotalFlexibleSize(axis);
                    }
                }

                float minMaxLerp = 0;
                if (GetTotalMinSize(axis) != GetTotalPreferredSize(axis))
                {
                    minMaxLerp = Mathf.Clamp01((size - GetTotalMinSize(axis)) / (GetTotalPreferredSize(axis) - GetTotalMinSize(axis)));
                }

                int initialIndex = isAxisDirty ? 0 : Mathf.Max(0, _initialDirtyIndex);
                for (int i = 0; i < children.Count; i++)
                {
                    IFastLayoutFeedback child = children[i];
                    float min, preferred, flexible;
                    GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible);

                    float scaleFactor = useScale && child.rectTransform != null? child.rectTransform.localScale[axis] : 1f;

                    Vector2 anchorMin, anchorMax;
                    GetChildAnchors(child, axis, controlSize, childForceExpandSize, defaultAnchor, out anchorMin, out anchorMax);

                    float childSize = Mathf.Lerp(min, preferred, minMaxLerp);
                    childSize += flexible * itemFlexibleMultiplier;

                    if (i >= initialIndex)
                    {
                        if (controlSize)
                        {
                            SetChildAlongAxisWithScale(child.rectTransform, axis, pos, childSize, scaleFactor, anchorMin, anchorMax);
                        }
                        else
                        {
                            var   sizeDelta    = axis == 0 ? child.cachedRectWidth : child.cachedRectHeight;
                            float offsetInCell = (childSize - sizeDelta) * alignmentOnAxis;
                            SetChildAlongAxisWithScale(child.rectTransform, axis, pos + offsetInCell, childSize, scaleFactor, anchorMin, anchorMax);
                        }
                    }
                    pos += childSize * scaleFactor + spacing;
                }
            }
        }