From 5d99f75ab6883067bfd34b96f7089ef35a61d02e Mon Sep 17 00:00:00 2001 From: Nic Barker Date: Mon, 3 Mar 2025 12:53:28 +1300 Subject: [PATCH] [Core] Improve grow & shrink handling consistency and edge cases --- clay.h | 139 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/clay.h b/clay.h index eea0ac4..6684a85 100644 --- a/clay.h +++ b/clay.h @@ -2018,54 +2018,9 @@ void Clay__InitializePersistentMemory(Clay_Context* context) { context->arenaResetOffset = arena->nextAllocation; } -void Clay__CompressChildrenAlongAxis(bool xAxis, float totalSizeToDistribute, Clay__int32_tArray resizableContainerBuffer) { - Clay_Context* context = Clay_GetCurrentContext(); - Clay__int32_tArray largestContainers = context->openClipElementStack; - - while (totalSizeToDistribute > 0.1) { - largestContainers.length = 0; - float largestSize = 0; - float targetSize = 0; - for (int32_t i = 0; i < resizableContainerBuffer.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i)); - float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height; - if ((childSize - largestSize) < 0.1 && (childSize - largestSize) > -0.1) { - Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i)); - } else if (childSize > largestSize) { - targetSize = largestSize; - largestSize = childSize; - largestContainers.length = 0; - Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i)); - } - else if (childSize > targetSize) { - targetSize = childSize; - } - } - - if (largestContainers.length == 0) { - return; - } - - targetSize = CLAY__MAX(targetSize, (largestSize * largestContainers.length) - totalSizeToDistribute) / largestContainers.length; - - for (int32_t childOffset = 0; childOffset < largestContainers.length; childOffset++) { - int32_t childIndex = Clay__int32_tArray_GetValue(&largestContainers, childOffset); - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex); - float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; - float childMinSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height; - float oldChildSize = *childSize; - *childSize = CLAY__MAX(childMinSize, targetSize); - totalSizeToDistribute -= (oldChildSize - *childSize); - if (*childSize == childMinSize) { - for (int32_t i = 0; i < resizableContainerBuffer.length; i++) { - if (Clay__int32_tArray_GetValue(&resizableContainerBuffer, i) == childIndex) { - Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, i); - break; - } - } - } - } - } +bool Clay__FloatEq(float left, float right) { + float subtracted = left - right; + return subtracted < 0.01 && subtracted > -0.01; } void Clay__SizeContainersAlongAxis(bool xAxis) { @@ -2168,25 +2123,81 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { } } // Scrolling containers preferentially compress before others - Clay__CompressChildrenAlongAxis(xAxis, -sizeToDistribute, resizableContainerBuffer); + while (sizeToDistribute < -0.1f && resizableContainerBuffer.length > 0) { + float largest = 0; + float secondLargest = 0; + float widthToAdd = sizeToDistribute; + for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); + float childSize = xAxis ? child->dimensions.width : child->dimensions.height; + if (childSize > largest) { + secondLargest = largest; + largest = childSize; + } + if (childSize < largest) { + secondLargest = CLAY__MAX(secondLargest, childSize); + widthToAdd = secondLargest - largest; + } + } + + widthToAdd = CLAY__MAX(widthToAdd, sizeToDistribute / resizableContainerBuffer.length); + + for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); + float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height; + float minSize = xAxis ? child->minDimensions.width : child->minDimensions.height; + float previousWidth = *childSize; + if (Clay__FloatEq(*childSize, largest)) { + *childSize += widthToAdd; + if (*childSize <= minSize) { + *childSize = minSize; + Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--); + } + sizeToDistribute -= (*childSize - previousWidth); + } + } + } // The content is too small, allow SIZING_GROW containers to expand } else if (sizeToDistribute > 0 && growContainerCount > 0) { - float targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount; - for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset)); - Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; - if (childSizing.type == CLAY__SIZING_TYPE_GROW) { - float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; - float *minSize = xAxis ? &childElement->minDimensions.width : &childElement->minDimensions.height; - if (targetSize < *minSize) { - growContainerContentSize -= *minSize; - Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childOffset); - growContainerCount--; - targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount; - childOffset = -1; - continue; + for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); + Clay__SizingType childSizing = xAxis ? child->layoutConfig->sizing.width.type : child->layoutConfig->sizing.height.type; + if (childSizing != CLAY__SIZING_TYPE_GROW) { + Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--); + } + } + while (sizeToDistribute > 0.1f && resizableContainerBuffer.length > 0) { + float smallest = CLAY__MAXFLOAT; + float secondSmallest = CLAY__MAXFLOAT; + float widthToAdd = sizeToDistribute; + for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); + float childSize = xAxis ? child->dimensions.width : child->dimensions.height; + if (childSize < smallest) { + secondSmallest = smallest; + smallest = childSize; + } + if (childSize > smallest) { + secondSmallest = CLAY__MIN(secondSmallest, childSize); + widthToAdd = secondSmallest - smallest; + } + } + + widthToAdd = CLAY__MIN(widthToAdd, sizeToDistribute / resizableContainerBuffer.length); + + for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); + float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height; + float maxSize = xAxis ? child->layoutConfig->sizing.width.size.minMax.max : child->layoutConfig->sizing.height.size.minMax.max; + float previousWidth = *childSize; + if (Clay__FloatEq(*childSize, smallest)) { + *childSize += widthToAdd; + if (*childSize >= maxSize) { + *childSize = maxSize; + Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--); + } + sizeToDistribute -= (*childSize - previousWidth); } - *childSize = targetSize; } } }