mirror of
https://github.com/nicbarker/clay.git
synced 2025-05-16 23:38:08 +00:00
Compare commits
2 Commits
5571c00a21
...
02bce89d17
Author | SHA1 | Date | |
---|---|---|---|
|
02bce89d17 | ||
|
b5b086af13 |
2
.github/workflows/cmake-multi-platform.yml
vendored
2
.github/workflows/cmake-multi-platform.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4.0.2
|
||||
uses: actions/cache@v4.2.0
|
||||
with:
|
||||
# A list of files, directories, and wildcard patterns to cache and restore
|
||||
path: "/home/runner/work/clay/clay/build/_deps"
|
||||
|
64
README.md
64
README.md
@ -897,18 +897,12 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_
|
||||
|
||||
### CLAY_ID
|
||||
|
||||
**Usage**
|
||||
|
||||
`CLAY(CLAY_ID(char* idString)) {}`
|
||||
|
||||
**Lifecycle**
|
||||
|
||||
`Clay_BeginLayout()` -> `CLAY(` -> `CLAY_ID()` -> `)` -> `Clay_EndLayout()`
|
||||
|
||||
**Notes**
|
||||
`Clay_ElementId CLAY_ID(STRING_LITERAL idString)`
|
||||
|
||||
**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.
|
||||
|
||||
**Examples**
|
||||
@ -931,11 +925,31 @@ 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_ElementId CLAY_IDI(char *label, int32_t index)`
|
||||
`Clay_ElementId CLAY_IDI(STRING_LITERAL idString, 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`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@ -943,7 +957,7 @@ An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_ele
|
||||
|
||||
**Usage**
|
||||
|
||||
`CLAY(CLAY_ID_LOCAL(char* idString)) {}`
|
||||
`Clay_ElementId CLAY_ID_LOCAL(STRING_LITERAL idString)`
|
||||
|
||||
**Lifecycle**
|
||||
|
||||
@ -957,6 +971,8 @@ 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.
|
||||
|
||||
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**
|
||||
|
||||
```C
|
||||
@ -976,11 +992,31 @@ 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_ElementId CLAY_IDI_LOCAL(char *label, int32_t index)`
|
||||
`Clay_ElementId CLAY_IDI_LOCAL(STRING_LITERAL idString, 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`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
|
||||
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.
|
||||
|
||||
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.
Binary file not shown.
Binary file not shown.
160
clay.h
160
clay.h
@ -71,13 +71,25 @@
|
||||
|
||||
#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_IDI(label, index) Clay__HashString(CLAY_STRING(label), index, 0)
|
||||
#define CLAY_SID(label) CLAY_SIDI(label, 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_IDI_LOCAL(label, index) Clay__HashString(CLAY_STRING(label), index, Clay__GetParentElementId())
|
||||
#define CLAY_SID_LOCAL(label) CLAY_SIDI_LOCAL(label, 0)
|
||||
|
||||
// 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]))
|
||||
|
||||
@ -2018,54 +2030,11 @@ 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;
|
||||
const float CLAY__EPSILON = 0.01;
|
||||
|
||||
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__FloatEqual(float left, float right) {
|
||||
float subtracted = left - right;
|
||||
return subtracted < CLAY__EPSILON && subtracted > -CLAY__EPSILON;
|
||||
}
|
||||
|
||||
void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
@ -2103,7 +2072,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
int32_t growContainerCount = 0;
|
||||
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 innerContentSize = 0, growContainerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
|
||||
float innerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
|
||||
bool sizingAlongAxis = (xAxis && parentStyleConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) || (!xAxis && parentStyleConfig->layoutDirection == CLAY_TOP_TO_BOTTOM);
|
||||
resizableContainerBuffer.length = 0;
|
||||
float parentChildGap = parentStyleConfig->childGap;
|
||||
@ -2129,7 +2098,6 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
if (sizingAlongAxis) {
|
||||
innerContentSize += (childSizing.type == CLAY__SIZING_TYPE_PERCENT ? 0 : childSize);
|
||||
if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
|
||||
growContainerContentSize += childSize;
|
||||
growContainerCount++;
|
||||
}
|
||||
if (childOffset > 0) {
|
||||
@ -2168,25 +2136,83 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
}
|
||||
}
|
||||
// Scrolling containers preferentially compress before others
|
||||
Clay__CompressChildrenAlongAxis(xAxis, -sizeToDistribute, resizableContainerBuffer);
|
||||
while (sizeToDistribute < -CLAY__EPSILON && 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 (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
|
||||
} 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 > CLAY__EPSILON && 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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user