mirror of
https://github.com/nicbarker/clay.git
synced 2025-05-16 15:28:03 +00:00
Compare commits
7 Commits
feb6c1ac35
...
1b6be4aec7
Author | SHA1 | Date | |
---|---|---|---|
|
1b6be4aec7 | ||
|
02bce89d17 | ||
|
b5b086af13 | ||
|
af3d63ad0f | ||
|
0eb162e3a3 | ||
|
d1fd147b09 | ||
|
13b588d8c1 |
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"
|
||||
|
73
README.md
73
README.md
@ -169,6 +169,7 @@ For help starting out or to discuss clay, considering joining [the discord serve
|
||||
- [Clay_SetCurrentContext](#clay_setcurrentcontext)
|
||||
- [Clay_SetLayoutDimensions](#clay_setlayoutdimensions)
|
||||
- [Clay_SetPointerState](#clay_setpointerstate)
|
||||
- [Clay_GetPointerState](#clay_getpointerstate)
|
||||
- [Clay_UpdateScrollContainers](#clay_updatescrollcontainers)
|
||||
- [Clay_BeginLayout](#clay_beginlayout)
|
||||
- [Clay_EndLayout](#clay_endlayout)
|
||||
@ -646,6 +647,14 @@ Sets the internal pointer position and state (i.e. current mouse / touch positio
|
||||
|
||||
---
|
||||
|
||||
### Clay_GetPointerState
|
||||
|
||||
`Clay_PointerData Clay_GetPointerState()`
|
||||
|
||||
Get the internal pointer position and state (i.e. current mouse / touch position). returns clay internal click start and stop state.
|
||||
|
||||
---
|
||||
|
||||
### Clay_UpdateScrollContainers
|
||||
|
||||
`void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime)`
|
||||
@ -897,18 +906,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 +934,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 +966,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 +980,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 +1001,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.
169
clay.h
169
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]))
|
||||
|
||||
@ -784,6 +796,9 @@ CLAY_DLL_EXPORT Clay_Arena Clay_CreateArenaWithCapacityAndMemory(size_t capacity
|
||||
// Sets the state of the "pointer" (i.e. the mouse or touch) in Clay's internal data. Used for detecting and responding to mouse events in the debug view,
|
||||
// as well as for Clay_Hovered() and scroll element handling.
|
||||
CLAY_DLL_EXPORT void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
|
||||
// Gets the state of the "pointer". This will return the position provided by `Clay_SetPointerState`
|
||||
// and the frame pressed state.
|
||||
CLAY_DLL_EXPORT Clay_PointerData Clay_GetPointerState();
|
||||
// Initialize Clay's internal arena and setup required data before layout can begin. Only needs to be called once.
|
||||
// - arena can be created using Clay_CreateArenaWithCapacityAndMemory()
|
||||
// - layoutDimensions are the initial bounding dimensions of the layout (i.e. the screen width and height for a full screen layout)
|
||||
@ -2018,54 +2033,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 +2075,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 +2101,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 +2139,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3706,6 +3735,12 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
|
||||
}
|
||||
}
|
||||
|
||||
CLAY_WASM_EXPORT("Clay_GetPointerState")
|
||||
Clay_PointerData Clay_GetPointerState() {
|
||||
Clay_Context* context = Clay_GetCurrentContext();
|
||||
return context->pointerInfo;
|
||||
}
|
||||
|
||||
CLAY_WASM_EXPORT("Clay_Initialize")
|
||||
Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) {
|
||||
Clay_Context *context = Clay__Context_Allocate_Arena(&arena);
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user