Compare commits

..

1 Commits

Author SHA1 Message Date
Harrison Lambeth
6daa446e97
Merge 38bb241ced into 5571c00a21 2025-03-03 11:14:38 +01:00
9 changed files with 82 additions and 144 deletions

View File

@ -53,7 +53,7 @@ jobs:
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Cache - name: Cache
uses: actions/cache@v4.2.0 uses: actions/cache@v4.0.2
with: with:
# A list of files, directories, and wildcard patterns to cache and restore # A list of files, directories, and wildcard patterns to cache and restore
path: "/home/runner/work/clay/clay/build/_deps" path: "/home/runner/work/clay/clay/build/_deps"

View File

@ -897,12 +897,18 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_
### CLAY_ID ### CLAY_ID
`Clay_ElementId CLAY_ID(STRING_LITERAL idString)` **Usage**
`CLAY(CLAY_ID(char* idString)) {}`
**Lifecycle**
`Clay_BeginLayout()` -> `CLAY(` -> `CLAY_ID()` -> `)` -> `Clay_EndLayout()`
**Notes**
**CLAY_ID()** is used to generate and attach a [Clay_ElementId](#clay_elementid) to a layout element during declaration. **CLAY_ID()** is used to generate and attach a [Clay_ElementId](#clay_elementid) to a layout element during declaration.
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SID](#clay_sid).
To regenerate the same ID outside of layout declaration when using utility functions such as [Clay_PointerOver](#clay_pointerover), use the [Clay_GetElementId](#clay_getelementid) function. To regenerate the same ID outside of layout declaration when using utility functions such as [Clay_PointerOver](#clay_pointerover), use the [Clay_GetElementId](#clay_getelementid) function.
**Examples** **Examples**
@ -925,31 +931,11 @@ if (buttonIsHovered && leftMouseButtonPressed) {
--- ---
### CLAY_SID()
`Clay_ElementId CLAY_SID(Clay_String idString)`
A version of [CLAY_ID](#clay_id) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
---
### CLAY_IDI() ### CLAY_IDI()
`Clay_ElementId CLAY_IDI(STRING_LITERAL idString, int32_t index)` `Clay_ElementId CLAY_IDI(char *label, int32_t index)`
An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SIDI](#clay_sidi).
---
### CLAY_SIDI()
`Clay_ElementId CLAY_SIDI(Clay_String idString, int32_t index)`
A version of [CLAY_IDI](#clay_idi) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
--- ---
@ -957,7 +943,7 @@ A version of [CLAY_IDI](#clay_idi) that can be used with heap allocated `char *`
**Usage** **Usage**
`Clay_ElementId CLAY_ID_LOCAL(STRING_LITERAL idString)` `CLAY(CLAY_ID_LOCAL(char* idString)) {}`
**Lifecycle** **Lifecycle**
@ -971,8 +957,6 @@ Unlike [CLAY_ID](#clay_id) which needs to be globally unique, a local ID is base
As a result, local id is suitable for use in reusable components and loops. As a result, local id is suitable for use in reusable components and loops.
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SID_LOCAL](#clay_sid_local).
**Examples** **Examples**
```C ```C
@ -992,31 +976,11 @@ for (int i = 0; i < headerButtons.length; i++) {
--- ---
### CLAY_SID_LOCAL()
`Clay_ElementId CLAY_SID_LOCAL(Clay_String idString)`
A version of [CLAY_ID_LOCAL](#clay_id_local) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
---
### CLAY_IDI_LOCAL() ### CLAY_IDI_LOCAL()
`Clay_ElementId CLAY_IDI_LOCAL(STRING_LITERAL idString, int32_t index)` `Clay_ElementId CLAY_IDI_LOCAL(char *label, int32_t index)`
An offset version of [CLAY_ID_LOCAL](#clay_local_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. An offset version of [CLAY_ID_LOCAL](#clay_local_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SIDI_LOCAL](#clay_sidi_local).
---
### CLAY_SIDI_LOCAL()
`Clay_ElementId CLAY_SIDI_LOCAL(Clay_String idString, int32_t index)`
A version of [CLAY_IDI_LOCAL](#clay_idi_local) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
--- ---

Binary file not shown.

Binary file not shown.

Binary file not shown.

160
clay.h
View File

@ -71,25 +71,13 @@
#define CLAY_SIZING_PERCENT(percentOfParent) (CLAY__INIT(Clay_SizingAxis) { .size = { .percent = (percentOfParent) }, .type = CLAY__SIZING_TYPE_PERCENT }) #define CLAY_SIZING_PERCENT(percentOfParent) (CLAY__INIT(Clay_SizingAxis) { .size = { .percent = (percentOfParent) }, .type = CLAY__SIZING_TYPE_PERCENT })
// Note: If a compile error led you here, you might be trying to use CLAY_ID with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID instead.
#define CLAY_ID(label) CLAY_IDI(label, 0) #define CLAY_ID(label) CLAY_IDI(label, 0)
#define CLAY_SID(label) CLAY_SIDI(label, 0) #define CLAY_IDI(label, index) Clay__HashString(CLAY_STRING(label), index, 0)
// Note: If a compile error led you here, you might be trying to use CLAY_IDI with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI instead.
#define CLAY_IDI(label, index) CLAY_SIDI(CLAY_STRING(label), index)
#define CLAY_SIDI(label, index) Clay__HashString(label, index, 0)
// Note: If a compile error led you here, you might be trying to use CLAY_ID_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID_LOCAL instead.
#define CLAY_ID_LOCAL(label) CLAY_IDI_LOCAL(label, 0) #define CLAY_ID_LOCAL(label) CLAY_IDI_LOCAL(label, 0)
#define CLAY_SID_LOCAL(label) CLAY_SIDI_LOCAL(label, 0) #define CLAY_IDI_LOCAL(label, index) Clay__HashString(CLAY_STRING(label), index, Clay__GetParentElementId())
// Note: If a compile error led you here, you might be trying to use CLAY_IDI_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI_LOCAL instead.
#define CLAY_IDI_LOCAL(label, index) CLAY_SIDI_LOCAL(CLAY_STRING(label), index)
#define CLAY_SIDI_LOCAL(label, index) Clay__HashString(label, index, Clay__GetParentElementId())
#define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0])) #define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0]))
@ -2030,11 +2018,54 @@ void Clay__InitializePersistentMemory(Clay_Context* context) {
context->arenaResetOffset = arena->nextAllocation; context->arenaResetOffset = arena->nextAllocation;
} }
const float CLAY__EPSILON = 0.01; void Clay__CompressChildrenAlongAxis(bool xAxis, float totalSizeToDistribute, Clay__int32_tArray resizableContainerBuffer) {
Clay_Context* context = Clay_GetCurrentContext();
Clay__int32_tArray largestContainers = context->openClipElementStack;
bool Clay__FloatEqual(float left, float right) { while (totalSizeToDistribute > 0.1) {
float subtracted = left - right; largestContainers.length = 0;
return subtracted < CLAY__EPSILON && subtracted > -CLAY__EPSILON; 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;
}
}
}
}
}
} }
void Clay__SizeContainersAlongAxis(bool xAxis) { void Clay__SizeContainersAlongAxis(bool xAxis) {
@ -2072,7 +2103,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
int32_t growContainerCount = 0; int32_t growContainerCount = 0;
float parentSize = xAxis ? parent->dimensions.width : parent->dimensions.height; float parentSize = xAxis ? parent->dimensions.width : parent->dimensions.height;
float parentPadding = (float)(xAxis ? (parent->layoutConfig->padding.left + parent->layoutConfig->padding.right) : (parent->layoutConfig->padding.top + parent->layoutConfig->padding.bottom)); float parentPadding = (float)(xAxis ? (parent->layoutConfig->padding.left + parent->layoutConfig->padding.right) : (parent->layoutConfig->padding.top + parent->layoutConfig->padding.bottom));
float innerContentSize = 0, totalPaddingAndChildGaps = parentPadding; float innerContentSize = 0, growContainerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
bool sizingAlongAxis = (xAxis && parentStyleConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) || (!xAxis && parentStyleConfig->layoutDirection == CLAY_TOP_TO_BOTTOM); bool sizingAlongAxis = (xAxis && parentStyleConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) || (!xAxis && parentStyleConfig->layoutDirection == CLAY_TOP_TO_BOTTOM);
resizableContainerBuffer.length = 0; resizableContainerBuffer.length = 0;
float parentChildGap = parentStyleConfig->childGap; float parentChildGap = parentStyleConfig->childGap;
@ -2098,6 +2129,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
if (sizingAlongAxis) { if (sizingAlongAxis) {
innerContentSize += (childSizing.type == CLAY__SIZING_TYPE_PERCENT ? 0 : childSize); innerContentSize += (childSizing.type == CLAY__SIZING_TYPE_PERCENT ? 0 : childSize);
if (childSizing.type == CLAY__SIZING_TYPE_GROW) { if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
growContainerContentSize += childSize;
growContainerCount++; growContainerCount++;
} }
if (childOffset > 0) { if (childOffset > 0) {
@ -2136,83 +2168,25 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
} }
} }
// Scrolling containers preferentially compress before others // Scrolling containers preferentially compress before others
while (sizeToDistribute < -CLAY__EPSILON && resizableContainerBuffer.length > 0) { Clay__CompressChildrenAlongAxis(xAxis, -sizeToDistribute, resizableContainerBuffer);
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 (Clay__FloatEqual(childSize, largest)) { continue; }
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__FloatEqual(*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 // The content is too small, allow SIZING_GROW containers to expand
} else if (sizeToDistribute > 0 && growContainerCount > 0) { } else if (sizeToDistribute > 0 && growContainerCount > 0) {
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { float targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount;
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) {
Clay__SizingType childSizing = xAxis ? child->layoutConfig->sizing.width.type : child->layoutConfig->sizing.height.type; Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset));
if (childSizing != CLAY__SIZING_TYPE_GROW) { Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height;
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--); 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;
while (sizeToDistribute > CLAY__EPSILON && resizableContainerBuffer.length > 0) { if (targetSize < *minSize) {
float smallest = CLAY__MAXFLOAT; growContainerContentSize -= *minSize;
float secondSmallest = CLAY__MAXFLOAT; Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childOffset);
float widthToAdd = sizeToDistribute; growContainerCount--;
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount;
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); childOffset = -1;
float childSize = xAxis ? child->dimensions.width : child->dimensions.height; continue;
if (Clay__FloatEqual(childSize, smallest)) { continue; }
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__FloatEqual(*childSize, smallest)) {
*childSize += widthToAdd;
if (*childSize >= maxSize) {
*childSize = maxSize;
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
}
sizeToDistribute -= (*childSize - previousWidth);
} }
*childSize = targetSize;
} }
} }
} }