static void _ZFP_ZFUILinearLayout_layoutVertical(ZF_IN ZFUILinearLayout *parent,
                                                 ZF_IN const ZFUISize &size,
                                                 ZF_IN zfbool positiveDirection)
{
    zfint requiredSize = 0;
    zfint totalWeight = 0;
    zfbool hasLayoutedChild = zffalse;
    zfint parentMarginX = ZFUIMarginGetX(parent->layoutChildMargin());
    zfint parentMarginY = ZFUIMarginGetY(parent->layoutChildMargin());
    for(zfindex i = 0; i < parent->childCount(); ++i)
    {
        ZFUIView *child = parent->childAtIndex(i);
        ZFUILinearLayoutParam *layoutParam = child->layoutParamT();
        if(!child->viewVisible() && !layoutParam->layoutReserveSpaceWhenNotVisible())
        {
            continue ;
        }
        zfint prevSpace = (hasLayoutedChild ? parent->layoutChildSpace() : 0);
        hasLayoutedChild = zftrue;

        zfint marginX = parentMarginX + ZFUIMarginGetX(layoutParam->layoutMargin());
        zfint marginY = parentMarginY + ZFUIMarginGetY(layoutParam->layoutMargin());
        if(layoutParam->layoutWeight() > 0)
        {
            totalWeight += layoutParam->layoutWeight();
        }
        else
        {
            switch(layoutParam->sizeParam().height)
            {
                case ZFUISizeType::e_Wrap:
                {
                    child->layoutMeasure(
                        ZFUISizeMake(
                            ZFUIViewLayoutParam::sizeHintMerge(
                                layoutParam->sizeHint().width,
                                ZFUIViewLayoutParam::sizeHintOffset(size.width, -marginX)),
                            layoutParam->sizeHint().height),
                        layoutParam->sizeParam());
                    requiredSize += child->layoutMeasuredSize().height;
                }
                    break;
                case ZFUISizeType::e_Fill:
                    requiredSize = size.height;
                    break;
                default:
                    zfCoreCriticalShouldNotGoHere();
                    return ;
            }
        }

        requiredSize += prevSpace + marginY;
    }
    hasLayoutedChild = zffalse;
    zfint flexibleSize = zfmMax(0, size.height - requiredSize);
    zfint offset = (positiveDirection ? 0 : size.height);
    for(zfindex i = 0; i < parent->childCount(); ++i)
    {
        ZFUIView *child = parent->childAtIndex(i);
        ZFUILinearLayoutParam *layoutParam = child->layoutParamT();
        if(!child->viewVisible() && !layoutParam->layoutReserveSpaceWhenNotVisible())
        {
            continue ;
        }
        zfint prevSpace = (hasLayoutedChild ? parent->layoutChildSpace() : 0);
        hasLayoutedChild = zftrue;

        zfint marginX = parentMarginX + ZFUIMarginGetX(layoutParam->layoutMargin());
        zfint marginY = parentMarginY + ZFUIMarginGetY(layoutParam->layoutMargin());
        zfint totalUsedSpace = prevSpace + marginY;
        if(layoutParam->layoutWeight() > 0)
        {
            child->layoutMeasure(
                ZFUISizeMake(
                    ZFUIViewLayoutParam::sizeHintMerge(
                        layoutParam->sizeHint().width,
                        ZFUIViewLayoutParam::sizeHintOffset(size.width, -marginX)),
                    ZFUIViewLayoutParam::sizeHintMerge(flexibleSize * layoutParam->layoutWeight() / totalWeight, layoutParam->sizeHint().height)
                ),
                ZFUISizeParamMake(
                    layoutParam->sizeParam().width,
                    ZFUISizeType::e_Fill
                ));
            flexibleSize -= child->layoutMeasuredSize().height;
            totalWeight -= layoutParam->layoutWeight();
        }
        else
        {
            if(layoutParam->sizeParam().height == ZFUISizeType::e_Fill)
            {
                child->layoutMeasure(
                    ZFUISizeMake(
                        ZFUIViewLayoutParam::sizeHintMerge(
                            layoutParam->sizeHint().width,
                            ZFUIViewLayoutParam::sizeHintOffset(size.width, -marginX)),
                        ZFUIViewLayoutParam::sizeHintMerge(
                            layoutParam->sizeHint().height,
                            positiveDirection ? zfmMax(size.height - offset - totalUsedSpace, 0) : zfmMax(offset - totalUsedSpace, 0))
                    ),
                    layoutParam->sizeParam());
            }
        }
        if(positiveDirection)
        {
            child->layout(ZFUIAlignApply(
                layoutParam->layoutAlign(),
                ZFUIRectMake(0, offset + prevSpace, size.width, child->layoutMeasuredSize().height + marginY),
                child->layoutMeasuredSize(),
                layoutParam->layoutMargin() + parent->layoutChildMargin()));
            offset += prevSpace + child->layoutMeasuredSize().height + marginY;
        }
        else
        {
            offset -= child->layoutMeasuredSize().height + marginY + prevSpace;
            child->layout(ZFUIAlignApply(
                layoutParam->layoutAlign(),
                ZFUIRectMake(0, offset, size.width, child->layoutMeasuredSize().height + marginY),
                child->layoutMeasuredSize(),
                layoutParam->layoutMargin() + parent->layoutChildMargin()));
        }
    }
}
static void _ZFP_ZFUIFlowLayout_layoutVertical(ZF_IN ZFUIFlowLayout *parent,
                                               ZF_IN const ZFUISize &size,
                                               ZF_IN zfbool positiveDirection)
{
    zfindex wrapIndex = 0;
    zfint lineSizeUsed = 0;
    while(wrapIndex < parent->childCount()) // for each line
    {
        zfint requiredSize = 0;
        zfint totalWeight = 0;
        zfbool hasLayoutedChild = zffalse;
        zfint parentMarginX = ZFUIMarginGetX(parent->layoutChildMargin());
        zfint parentMarginY = ZFUIMarginGetY(parent->layoutChildMargin());
        zfindex wrapIndexTmp = parent->childCount();
        zfint lineSize = 0;
        zfint prevLineSpace = (wrapIndex > 0 ? parent->layoutChildSpaceX() : 0);
        zfint flexableWrapSize = 0;
        for(zfindex i = wrapIndex; i < parent->childCount(); ++i)
        {
            ZFUIView *child = parent->childAtIndex(i);
            ZFUIFlowLayoutParam *layoutParam = child->layoutParamT();
            if(!child->viewVisible() && !layoutParam->layoutReserveSpaceWhenNotVisible())
            {
                continue ;
            }
            zfint prevSpace = (hasLayoutedChild ? parent->layoutChildSpaceY() : 0);
            hasLayoutedChild = zftrue;

            zfint marginX = parentMarginX + ZFUIMarginGetX(layoutParam->layoutMargin());
            zfint marginY = parentMarginY + ZFUIMarginGetY(layoutParam->layoutMargin());
            zfint childRequiredSize = 0;
            if(layoutParam->layoutWeight() > 0)
            {
                child->layoutMeasure(
                    ZFUISizeMake(
                        ZFUIViewLayoutParam::sizeHintMerge(
                            layoutParam->sizeHint().width,
                            ZFUIViewLayoutParam::sizeHintOffset(size.width, 0 - lineSizeUsed - marginX - prevLineSpace)),
                        layoutParam->sizeHint().height),
                    layoutParam->sizeParam());
                childRequiredSize += child->layoutMeasuredSize().height;
            }
            else
            {
                switch(layoutParam->sizeParam().height)
                {
                    case ZFUISizeType::e_Wrap:
                        child->layoutMeasure(
                            ZFUISizeMake(
                                ZFUIViewLayoutParam::sizeHintMerge(
                                    layoutParam->sizeHint().width,
                                    ZFUIViewLayoutParam::sizeHintOffset(size.width, 0 - lineSizeUsed - marginX - prevLineSpace)),
                                layoutParam->sizeHint().height),
                            layoutParam->sizeParam());
                        childRequiredSize += child->layoutMeasuredSize().height;
                        break;
                    case ZFUISizeType::e_Fill:
                        child->layoutMeasure(
                            ZFUISizeMake(
                                ZFUIViewLayoutParam::sizeHintMerge(
                                    layoutParam->sizeHint().width,
                                    ZFUIViewLayoutParam::sizeHintOffset(size.width, 0 - lineSizeUsed - marginX - prevLineSpace)),
                                layoutParam->sizeHint().height),
                            layoutParam->sizeParam());
                        childRequiredSize = zfmMax(
                            child->layoutMeasuredSize().height,
                            size.height - requiredSize - prevSpace - marginY);
                        break;
                    default:
                        zfCoreCriticalShouldNotGoHere();
                        return ;
                }
            }
            childRequiredSize += prevSpace + marginY;
            if(i > wrapIndex && requiredSize + childRequiredSize > size.height)
            {
                wrapIndexTmp = i;
                break;
            }

            if(layoutParam->layoutWeight() > 0)
            {
                flexableWrapSize += childRequiredSize;
            }
            requiredSize += childRequiredSize;
            lineSize = zfmMax(lineSize, child->layoutMeasuredSize().width + marginX);
            if(layoutParam->layoutWeight() > 0)
            {
                totalWeight += layoutParam->layoutWeight();
            }
            if(requiredSize >= size.height)
            {
                wrapIndexTmp = i + 1;
                break;
            }
        }
        hasLayoutedChild = zffalse;
        zfint flexibleSize = zfmMax(0, size.height - requiredSize + flexableWrapSize);
        zfint offset = (positiveDirection ? 0 : size.height);
        zfint lineX = ((_ZFP_ZFUIFlowLayout_layoutOrientationSecondary(
                parent->layoutOrientationMain(), parent->layoutOrientationSecondary()) == ZFUIOrientation::e_Left)
            ? lineSizeUsed + prevLineSpace
            : size.width - lineSizeUsed - lineSize - prevLineSpace);
        for(zfindex i = wrapIndex; i < wrapIndexTmp; ++i)
        {
            ZFUIView *child = parent->childAtIndex(i);
            ZFUIFlowLayoutParam *layoutParam = child->layoutParamT();
            if(!child->viewVisible() && !layoutParam->layoutReserveSpaceWhenNotVisible())
            {
                continue ;
            }
            zfint prevSpace = (hasLayoutedChild ? parent->layoutChildSpaceY() : 0);
            hasLayoutedChild = zftrue;

            zfint marginX = parentMarginX + ZFUIMarginGetX(layoutParam->layoutMargin());
            zfint marginY = parentMarginY + ZFUIMarginGetY(layoutParam->layoutMargin());
            zfint totalUsedSpace = prevSpace + marginY;
            if(layoutParam->layoutWeight() > 0)
            {
                child->layoutMeasure(
                    ZFUISizeMake(
                        ZFUIViewLayoutParam::sizeHintMerge(
                            layoutParam->sizeHint().width,
                            ZFUIViewLayoutParam::sizeHintOffset(size.width, 0 - lineSizeUsed - marginX - prevLineSpace)),
                        ZFUIViewLayoutParam::sizeHintMerge(flexibleSize * layoutParam->layoutWeight() / totalWeight, layoutParam->sizeHint().height)
                        ),
                    ZFUISizeParamMake(
                        layoutParam->sizeParam().width,
                        ZFUISizeType::e_Fill
                        ));
                flexibleSize -= child->layoutMeasuredSize().height;
                totalWeight -= layoutParam->layoutWeight();
            }
            else
            {
                if(layoutParam->sizeParam().height == ZFUISizeType::e_Fill)
                {
                    child->layoutMeasure(
                        ZFUISizeMake(
                            ZFUIViewLayoutParam::sizeHintMerge(
                                layoutParam->sizeHint().width,
                                ZFUIViewLayoutParam::sizeHintOffset(size.width, 0 - lineSizeUsed - marginX - prevLineSpace)),
                            ZFUIViewLayoutParam::sizeHintMerge(
                                layoutParam->sizeHint().height,
                                positiveDirection ? zfmMax(size.height - offset - totalUsedSpace, 0) : zfmMax(offset - totalUsedSpace, 0))
                            ),
                        layoutParam->sizeParam());
                }
            }
            if(positiveDirection)
            {
                child->layout(ZFUIAlignApply(
                    layoutParam->layoutAlign(),
                    ZFUIRectMake(lineX, offset + prevSpace, lineSize, child->layoutMeasuredSize().height + marginY),
                    child->layoutMeasuredSize(),
                    layoutParam->layoutMargin() + parent->layoutChildMargin()));
                offset += prevSpace + child->layoutMeasuredSize().height + marginY;
            }
            else
            {
                offset -= child->layoutMeasuredSize().height + marginY + prevSpace;
                child->layout(ZFUIAlignApply(
                    layoutParam->layoutAlign(),
                    ZFUIRectMake(lineX, offset, lineSize, child->layoutMeasuredSize().height + marginY),
                    child->layoutMeasuredSize(),
                    layoutParam->layoutMargin() + parent->layoutChildMargin()));
            }
        } // for(zfindex i = wrapIndex; i < wrapIndexTmp; ++i)
        wrapIndex = wrapIndexTmp;
        lineSizeUsed += lineSize + prevLineSpace;
    } // for each line
}