From ffc3b13d238494ad7e852b59d6df4033f8238a67 Mon Sep 17 00:00:00 2001 From: Nic Barker Date: Wed, 8 Jan 2025 16:24:11 +1300 Subject: [PATCH] Improve size distribution when shrinking --- clay.h | 95 +++++++++++++++++++++++++--------------------------------- 1 file changed, 40 insertions(+), 55 deletions(-) diff --git a/clay.h b/clay.h index 18a43963..ed20b508 100644 --- a/clay.h +++ b/clay.h @@ -2103,65 +2103,50 @@ CLAY__TYPEDEF(Clay__SizeDistributionType, enum { CLAY__SIZE_DISTRIBUTION_TYPE_GROW_CONTAINER, }); -float Clay__DistributeSizeAmongChildren(bool xAxis, float sizeToDistribute, Clay__int32_tArray resizableContainerBuffer, Clay__SizeDistributionType distributionType) { - Clay__int32_tArray remainingElements = Clay__openClipElementStack; - remainingElements.length = 0; - - for (int32_t i = 0; i < resizableContainerBuffer.length; ++i) { - Clay__int32_tArray_Add(&remainingElements, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); - } - - while (sizeToDistribute != 0 && remainingElements.length > 0) { - float dividedSize = sizeToDistribute / (float)remainingElements.length; - for (int32_t childOffset = 0; childOffset < remainingElements.length; childOffset++) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&remainingElements, childOffset)); - Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; - float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; - float childMinSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height; - bool canDistribute = true; - - if ((sizeToDistribute < 0 && *childSize == childSizing.size.minMax.min) || (sizeToDistribute > 0 && *childSize == childSizing.size.minMax.max)) { - canDistribute = false; +float Clay__DistributeSizeAmongChildren(bool xAxis, float totalSizeToDistribute, Clay__int32_tArray resizableContainerBuffer, Clay__SizeDistributionType distributionType) { + Clay__int32_tArray largestContainers = Clay__openClipElementStack; + largestContainers.length = 0; + + while (totalSizeToDistribute > 0) { + float largestSize = 0; + float targetSize = 0; + for (uint32_t i = 0; i < resizableContainerBuffer.length; ++i) { + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); + float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height; + if (childSize == largestSize) { + Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); + } else if (childSize > largestSize) { + largestSize = childSize; + largestContainers.length = 0; + Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); } - // Currently, we don't support squishing aspect ratio images on their Y axis as it would break ratio - else if (!xAxis && Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) { - canDistribute = false; - } - else { - switch (distributionType) { - case CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER: break; - case CLAY__SIZE_DISTRIBUTION_TYPE_GROW_CONTAINER: if (childSizing.type != CLAY__SIZING_TYPE_GROW) canDistribute = false; break; - case CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER: { - if (Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER)) { - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(childElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig; - if ((xAxis && !scrollConfig->horizontal) || (!xAxis && !scrollConfig->vertical)) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); - childOffset--; - continue; - } - } - } - } + else if (childSize > targetSize) { + targetSize = childSize; } + } - if (!canDistribute) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); - childOffset--; - continue; - } + targetSize = CLAY__MAX(targetSize, (largestSize * largestContainers.length) - totalSizeToDistribute) / largestContainers.length; + for (uint32_t childOffset = 0; childOffset < largestContainers.length; childOffset++) { + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, + Clay__int32_tArray_Get(&largestContainers, + childOffset)); + float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; + float childMinSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height; float oldChildSize = *childSize; - *childSize = CLAY__MAX(CLAY__MAX(CLAY__MIN(childSizing.size.minMax.max, *childSize + dividedSize), childSizing.size.minMax.min), childMinSize); - float diff = *childSize - oldChildSize; - if (diff > -0.01 && diff < 0.01) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); + *childSize = CLAY__MAX(childMinSize, targetSize); + totalSizeToDistribute -= (oldChildSize - *childSize); + if (*childSize == childMinSize) { + Clay__int32_tArray_RemoveSwapback(&largestContainers, childOffset); childOffset--; - continue; } - sizeToDistribute -= diff; + } + + if (largestContainers.length == 0) { + break; } } - return (sizeToDistribute > -0.01 && sizeToDistribute < 0.01) ? 0 : sizeToDistribute; + return (totalSizeToDistribute > -0.01 && totalSizeToDistribute < 0.01) ? 0 : totalSizeToDistribute; } void Clay__SizeContainersAlongAxis(bool xAxis) { @@ -2264,12 +2249,12 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { } } // Scrolling containers preferentially compress before others - sizeToDistribute = Clay__DistributeSizeAmongChildren(xAxis, sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER); + sizeToDistribute = Clay__DistributeSizeAmongChildren(xAxis, -sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER); - // If there is still height to make up, remove it from all containers that haven't hit their minimum size - if (sizeToDistribute < 0) { - Clay__DistributeSizeAmongChildren(xAxis, sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER); - } +// // If there is still height to make up, remove it from all containers that haven't hit their minimum size +// if (sizeToDistribute < 0) { +// Clay__DistributeSizeAmongChildren(xAxis, sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER); +// } // The content is too small, allow SIZING_GROW containers to expand } else if (sizeToDistribute > 0 && growContainerCount > 0) { float targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount;