Fixes for html renderer

This commit is contained in:
Nic Barker 2024-10-16 11:09:32 +13:00
parent c496ddd853
commit 6fdabc85cf
5 changed files with 326 additions and 200 deletions

399
clay.h
View File

@ -70,7 +70,7 @@
#define CLAY_ID_LOCAL(label) CLAY_IDI_LOCAL(label, 0)
#define CLAY_IDI_LOCAL(label, index) Clay__AttachId(Clay__HashString(CLAY_STRING(label), Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2))->children.length, Clay__GetOpenLayoutElement()->id))
#define CLAY_IDI_LOCAL(label, index) Clay__AttachId(Clay__HashString(CLAY_STRING(label), Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2))->children.length + 1, Clay__GetOpenLayoutElement()->id))
#define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0]))
@ -391,6 +391,9 @@ typedef struct
Clay_String text; // TODO I wish there was a way to avoid having to have this on every render command
uint32_t id;
Clay_RenderCommandType commandType;
#ifdef CLAY_DEBUG
Clay_String name;
#endif
} Clay_RenderCommand;
typedef struct
@ -400,8 +403,22 @@ typedef struct
Clay_RenderCommand *internalArray;
} Clay_RenderCommandArray;
typedef enum
{
CLAY_POINTER_INFO_PRESSED_THIS_FRAME,
CLAY_POINTER_INFO_PRESSED,
CLAY_POINTER_INFO_RELEASED_THIS_FRAME,
CLAY_POINTER_INFO_RELEASED,
} Clay_PointerInfoMouseDownState;
typedef struct
{
Clay_Vector2 position;
Clay_PointerInfoMouseDownState state;
} Clay_PointerInfo;
// Function Forward Declarations ---------------------------------
// Public API functions
// Public API functions ---
uint32_t Clay_MinMemorySize();
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset);
void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
@ -410,7 +427,8 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe
void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
void Clay_BeginLayout();
Clay_RenderCommandArray Clay_EndLayout();
bool Clay_PointerOver(Clay_ElementId id);
bool Clay_Hovered();
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerInfo pointerInfo, intptr_t userData), intptr_t userData);
Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config));
Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
@ -422,7 +440,7 @@ void Clay__CloseElement();
// Internal API functions required by macros
Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config);
void Clay__ElementPostConfiguration();
Clay_ElementId Clay__AttachId(Clay_ElementId id);
void Clay__AttachId(Clay_ElementId id);
void Clay__AttachLayoutConfig(Clay_LayoutConfig *config);
void Clay__AttachElementConfig(Clay_ElementConfigUnion config, Clay__ElementConfigType type);
Clay_RectangleElementConfig * Clay__StoreRectangleElementConfig(Clay_RectangleElementConfig config);
@ -474,7 +492,7 @@ bool Clay__warningsEnabled = true;
void Clay__Noop() {};
Clay_String CLAY__SPACECHAR = CLAY__INIT(Clay_String) { .length = 1, .chars = " " };
Clay_String CLAY__STRING_DEFAULT = CLAY__INIT(Clay_String) { .length = 0, .chars = "" };
Clay_String CLAY__STRING_DEFAULT = CLAY__INIT(Clay_String) { .length = 0, .chars = NULL };
typedef struct
{
@ -651,7 +669,7 @@ Clay_ElementConfig *Clay__ElementConfigArraySlice_Get(Clay__ElementConfigArraySl
#pragma endregion
// __GENERATED__ template
Clay_LayoutConfig CLAY_LAYOUT_DEFAULT = CLAY__INIT(Clay_LayoutConfig){};
Clay_LayoutConfig CLAY_LAYOUT_DEFAULT = CLAY__INIT(Clay_LayoutConfig){ .sizing = { .width = { .type = CLAY__SIZING_TYPE_FIT, .sizeMinMax = {0, CLAY__MAXFLOAT }}, .height = { .type = CLAY__SIZING_TYPE_FIT, .sizeMinMax = {0, CLAY__MAXFLOAT }} } };
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_LayoutConfig NAME=Clay__LayoutConfigArray DEFAULT_VALUE=&CLAY_LAYOUT_DEFAULT
#pragma region generated
@ -1079,11 +1097,13 @@ Clay__DebugElementData *Clay__DebugElementDataArray_Get(Clay__DebugElementDataAr
#pragma endregion
// __GENERATED__ template
typedef struct
typedef struct // todo get this struct into a single cache line
{
Clay_BoundingBox boundingBox;
Clay_ElementId elementId;
Clay_LayoutElement* layoutElement;
void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerInfo pointerInfo, intptr_t userData);
intptr_t hoverFunctionUserData;
int32_t nextIndex;
uint32_t generation;
Clay__DebugElementData *debugData;
@ -1339,21 +1359,7 @@ Clay_String Clay__WriteStringToCharBuffer(Clay__CharArray *buffer, Clay_String s
return CLAY__INIT(Clay_String) { .length = string.length, .chars = (const char *)(buffer->internalArray + buffer->length - string.length) };
}
typedef enum
{
CLAY__POINTER_INFO_PRESSED_THIS_FRAME,
CLAY__POINTER_INFO_PRESSED,
CLAY__POINTER_INFO_RELEASED_THIS_FRAME,
CLAY__POINTER_INFO_RELEASED,
} Clay__PointerInfoMouseDownState;
typedef struct
{
Clay_Vector2 position;
Clay__PointerInfoMouseDownState state;
} Clay__PointerInfo;
Clay__PointerInfo Clay__pointerInfo = CLAY__INIT(Clay__PointerInfo) { .position = {-1, -1} };
Clay_PointerInfo Clay__pointerInfo = CLAY__INIT(Clay_PointerInfo) { .position = {-1, -1} };
Clay_Dimensions Clay__layoutDimensions = CLAY__INIT(Clay_Dimensions){};
Clay_ElementId Clay__dynamicElementIndexBaseHash = CLAY__INIT(Clay_ElementId) { .id = 128476991, .stringId = { .length = 8, .chars = "Auto ID" } };
uint32_t Clay__dynamicElementIndex = 0;
@ -1426,6 +1432,18 @@ Clay_ElementConfigUnion Clay__FindElementConfigWithType(Clay_LayoutElement *elem
return CLAY__INIT(Clay_ElementConfigUnion) { NULL };
}
Clay_ElementId Clay__HashNumber(const uint32_t offset, const uint32_t seed) {
uint32_t hash = seed;
hash += (offset + 48);
hash += (hash << 10);
hash ^= (hash >> 6);
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = seed, .stringId = CLAY__STRING_DEFAULT }; // Reserve the hash result of zero as "null id"
}
Clay_ElementId Clay__HashString(Clay_String key, const uint32_t offset, const uint32_t seed) {
uint32_t hash = 0;
uint32_t base = seed;
@ -1473,10 +1491,6 @@ uint32_t Clay__RehashWithNumber(uint32_t id, uint32_t number) {
}
uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *config) {
union {
float fontSize;
uint32_t bits;
} fontSizeBits = { .fontSize = (float)config->fontSize };
uint32_t hash = 0;
uint64_t pointerAsNumber = (uint64_t)text->chars;
@ -1488,11 +1502,8 @@ uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *con
hash += (hash << 10);
hash ^= (hash >> 6);
hash += config->fontId;
hash += (hash << 10);
hash ^= (hash >> 6);
hash += fontSizeBits.bits;
uint64_t configPointerAsNumber = (uint64_t)config;
hash += configPointerAsNumber;
hash += (hash << 10);
hash ^= (hash >> 6);
@ -1574,12 +1585,14 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
}
end++;
}
Clay_String lastWord = CLAY__INIT(Clay_String) { .length = (int)(end - start), .chars = &text->chars[start] };
Clay_Dimensions dimensions = Clay__MeasureText(&lastWord, config);
Clay__MeasuredWordArray_Add(&Clay__measuredWords, CLAY__INIT(Clay__MeasuredWord) { .word = lastWord, .startOffset = start, .length = end - start, .width = dimensions.width });
measuredWidth += dimensions.width;
measuredHeight = dimensions.height;
measured->measuredWords.length++;
if (end - start > 0) {
Clay_String lastWord = CLAY__INIT(Clay_String) { .length = (int)(end - start), .chars = &text->chars[start] };
Clay_Dimensions dimensions = Clay__MeasureText(&lastWord, config);
Clay__MeasuredWordArray_Add(&Clay__measuredWords, CLAY__INIT(Clay__MeasuredWord) { .word = lastWord, .startOffset = start, .length = end - start, .width = dimensions.width });
measuredWidth += dimensions.width;
measuredHeight = dimensions.height;
measured->measuredWords.length++;
}
measured->unwrappedDimensions.width = measuredWidth;
measured->unwrappedDimensions.height = measuredHeight;
@ -1644,18 +1657,22 @@ Clay_LayoutElementHashMapItem *Clay__GetHashMapItem(uint32_t id) {
return CLAY__NULL;
}
void Clay__GenerateIdForAnonymousElement(Clay_LayoutElement *openLayoutElement) {
Clay_LayoutElement *parentElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2));
Clay_ElementId elementId = Clay__HashNumber(parentElement->children.length, parentElement->id);
openLayoutElement->id = elementId.id;
Clay__AddHashMapItem(elementId, openLayoutElement);
Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId);
#ifdef CLAY_DEBUG
openLayoutElement->name = elementId.stringId;
#endif
}
void Clay__ElementPostConfiguration() {
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
// ID
if (openLayoutElement->id == 0) {
Clay_LayoutElement *parentElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2));
Clay_ElementId elementId = Clay__HashString(CLAY_STRING("auto"), parentElement->children.length, parentElement->id);
openLayoutElement->id = elementId.id;
Clay__AddHashMapItem(elementId, openLayoutElement);
Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId);
#ifdef CLAY_DEBUG
openLayoutElement->name = elementId.stringId;
#endif
Clay__GenerateIdForAnonymousElement(openLayoutElement);
}
// Layout Config
if (!openLayoutElement->layoutConfig) {
@ -1674,6 +1691,9 @@ void Clay__ElementPostConfiguration() {
Clay_FloatingElementConfig *floatingConfig = config->config.floatingElementConfig;
// This looks dodgy but because of the auto generated root element the depth of the tree will always be at least 2 here
Clay_LayoutElement *hierarchicalParent = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2));
if (!hierarchicalParent) {
break;
}
int clipElementId = 0;
if (floatingConfig->parentId == 0) {
// If no parent id was specified, attach to the elements direct hierarchical parent
@ -1895,7 +1915,7 @@ void Clay__InitializePersistentMemory(Clay_Arena *arena) {
Clay__measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT * 2, arena);
Clay__pointerOverIds = Clay__ElementIdArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__debugElementData = Clay__DebugElementDataArray_Allocate_Arena(CLAY_MAX_ELEMENT_COUNT, arena);
Clay__arenaResetOffset = arena->nextAllocation;
@ -2142,6 +2162,11 @@ void Clay__CalculateFinalLayout() {
float lineHeight = textConfig->lineHeight > 0 ? textConfig->lineHeight : textElementData->preferredDimensions.height;
uint32_t lineLengthChars = 0;
uint32_t lineStartOffset = 0;
if (textElementData->preferredDimensions.width <= containerElement->dimensions.width) {
Clay__StringArray_Add(&Clay__wrappedTextLines, textElementData->text);
textElementData->wrappedLines.length++;
continue;
}
for (int wordIndex = 0; wordIndex < measureTextCacheItem->measuredWords.length; ++wordIndex) {
Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArraySlice_Get(&measureTextCacheItem->measuredWords, wordIndex);
// measuredWord->length == 0 means a newline character
@ -2351,9 +2376,28 @@ void Clay__CalculateFinalLayout() {
hashMapItem->boundingBox = currentElementBoundingBox;
}
int sortedConfigIndexes[20];
for (int elementConfigIndex = 0; elementConfigIndex < currentElement->elementConfigs.length; ++elementConfigIndex) {
sortedConfigIndexes[elementConfigIndex] = elementConfigIndex;
}
int sortMax = currentElement->elementConfigs.length - 1;
while (sortMax > 0) { // dumb bubble sort
for (int i = 0; i < sortMax; ++i) {
int current = sortedConfigIndexes[i];
int next = sortedConfigIndexes[i + 1];
Clay__ElementConfigType currentType = Clay__ElementConfigArraySlice_Get(&currentElement->elementConfigs, current)->type;
Clay__ElementConfigType nextType = Clay__ElementConfigArraySlice_Get(&currentElement->elementConfigs, next)->type;
if (nextType == CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER || currentType == CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER) {
sortedConfigIndexes[i] = next;
sortedConfigIndexes[i + 1] = current;
}
}
sortMax--;
}
// Create the render commands for this element
for (int elementConfigIndex = 0; elementConfigIndex < currentElement->elementConfigs.length; ++elementConfigIndex) {
Clay_ElementConfig *elementConfig = Clay__ElementConfigArraySlice_Get(&currentElement->elementConfigs, elementConfigIndex);
Clay_ElementConfig *elementConfig = Clay__ElementConfigArraySlice_Get(&currentElement->elementConfigs, sortedConfigIndexes[elementConfigIndex]);
Clay_RenderCommand renderCommand = CLAY__INIT(Clay_RenderCommand) {
.boundingBox = currentElementBoundingBox,
.config = elementConfig->config,
@ -2406,7 +2450,7 @@ void Clay__CalculateFinalLayout() {
.boundingBox = { currentElementBoundingBox.x, currentElementBoundingBox.y + yPosition, (float)50, naturalLineHeight }, // TODO width
.config = configUnion,
.text = wrappedLine,
.id = Clay__RehashWithNumber(currentElement->id, 5 + lineIndex),
.id = Clay__HashNumber(lineIndex, currentElement->id).id,
.commandType = CLAY_RENDER_COMMAND_TYPE_TEXT,
});
yPosition += finalLineHeight;
@ -2425,41 +2469,6 @@ void Clay__CalculateFinalLayout() {
}
if (shouldRender) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, renderCommand);
// Render border elements between children as additional rectangles if specified
if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)) {
Clay_BorderElementConfig *borderConfig = elementConfig->config.borderElementConfig;
if (borderConfig->betweenChildren.width > 0 && borderConfig->betweenChildren.color.a > 0) {
Clay_RectangleElementConfig *rectangleConfig = Clay__StoreRectangleElementConfig(CLAY__INIT(Clay_RectangleElementConfig) {.color = borderConfig->betweenChildren.color});
Clay_Vector2 borderOffset = { (float)layoutConfig->padding.x, (float)layoutConfig->padding.y };
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
for (int i = 0; i < currentElement->children.length; ++i) {
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->children.elements[i]);
if (i > 0) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, CLAY__INIT(Clay_RenderCommand) {
.boundingBox = { currentElementBoundingBox.x + borderOffset.x, currentElementBoundingBox.y, (float)borderConfig->betweenChildren.width, currentElement->dimensions.height },
.config = { rectangleConfig },
.id = Clay__RehashWithNumber(currentElement->id, 5 + i),
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
});
}
borderOffset.x += (childElement->dimensions.width + (float)layoutConfig->childGap / 2);
}
} else {
for (int i = 0; i < currentElement->children.length; ++i) {
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->children.elements[i]);
if (i > 0) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, CLAY__INIT(Clay_RenderCommand) {
.boundingBox = { currentElementBoundingBox.x, currentElementBoundingBox.y + borderOffset.y, currentElement->dimensions.width, (float)borderConfig->betweenChildren.width },
.config = { rectangleConfig },
.id = Clay__RehashWithNumber(currentElement->id, 5 + i),
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
});
}
borderOffset.y += (childElement->dimensions.height + (float)layoutConfig->childGap / 2);
}
}
}
}
}
if (offscreen) {
// NOTE: You may be tempted to try an early return / continue if an element is off screen. Why bother calculating layout for its children, right?
@ -2508,12 +2517,64 @@ void Clay__CalculateFinalLayout() {
}
else {
// DFS is returning upwards backwards
bool closeScrollElement = false;
if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER)) {
closeScrollElement = true;
Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig;
// todo get rid of this annoying duplication just for handling borders between elements
for (int i = 0; i < Clay__scrollContainerDatas.length; i++) {
Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i);
if (mapping->layoutElement == currentElement) {
if (scrollConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; }
if (scrollConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; }
break;
}
}
}
if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)) {
Clay_LayoutElementHashMapItem *currentElementData = Clay__GetHashMapItem(currentElement->id);
Clay_BoundingBox currentElementBoundingBox = currentElementData->boundingBox;
Clay_BorderElementConfig *borderConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER).borderElementConfig;
if (borderConfig->betweenChildren.width > 0 && borderConfig->betweenChildren.color.a > 0) {
Clay_RectangleElementConfig *rectangleConfig = Clay__StoreRectangleElementConfig(CLAY__INIT(Clay_RectangleElementConfig) {.color = borderConfig->betweenChildren.color});
Clay_Vector2 borderOffset = { (float)layoutConfig->padding.x, (float)layoutConfig->padding.y };
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
for (int i = 0; i < currentElement->children.length; ++i) {
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->children.elements[i]);
if (i > 0) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, CLAY__INIT(Clay_RenderCommand) {
.boundingBox = { currentElementBoundingBox.x + borderOffset.x + scrollOffset.x, currentElementBoundingBox.y + scrollOffset.y, (float)borderConfig->betweenChildren.width, currentElement->dimensions.height },
.config = { rectangleConfig },
.id = Clay__RehashWithNumber(currentElement->id, 5 + i),
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
});
}
borderOffset.x += (childElement->dimensions.width + (float)layoutConfig->childGap / 2);
}
} else {
for (int i = 0; i < currentElement->children.length; ++i) {
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->children.elements[i]);
if (i > 0) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, CLAY__INIT(Clay_RenderCommand) {
.boundingBox = { currentElementBoundingBox.x + scrollOffset.x, currentElementBoundingBox.y + borderOffset.y + scrollOffset.y, currentElement->dimensions.width, (float)borderConfig->betweenChildren.width },
.config = { rectangleConfig },
.id = Clay__RehashWithNumber(currentElement->id, 5 + i),
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
});
}
borderOffset.y += (childElement->dimensions.height + (float)layoutConfig->childGap / 2);
}
}
}
}
// This exists because the scissor needs to end _after_ borders between elements
if (closeScrollElement) {
Clay_RenderCommandArray_Add(&Clay__renderCommands, CLAY__INIT(Clay_RenderCommand) {
.id = Clay__RehashWithNumber(currentElement->id, 11),
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END,
});
}
dfsBuffer.length--;
continue;
}
@ -2562,6 +2623,10 @@ void Clay__CalculateFinalLayout() {
} else {
currentElementTreeNode->nextChildOffset.y += childElement->dimensions.height + (float)layoutConfig->childGap;
}
if (currentElementTreeNode->nextChildOffset.x > 10000) {
continue;
}
}
}
}
@ -2572,7 +2637,11 @@ void Clay__CalculateFinalLayout() {
}
}
Clay_ElementId Clay__AttachId(Clay_ElementId elementId) {
Clay_ElementId Clay_GetElementId(Clay_String idString) {
return Clay__HashString(idString, 0, 0);
}
void Clay__AttachId(Clay_ElementId elementId) {
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
openLayoutElement->id = elementId.id;
Clay__AddHashMapItem(elementId, openLayoutElement);
@ -2580,10 +2649,13 @@ Clay_ElementId Clay__AttachId(Clay_ElementId elementId) {
#ifdef CLAY_DEBUG
openLayoutElement->name = elementId.stringId;
#endif
return elementId;
}
void Clay__AttachLayoutConfig(Clay_LayoutConfig *config) {
Clay__GetOpenLayoutElement()->layoutConfig = config;
if (config->childGap > 100) {
return;
}
}
void Clay__AttachElementConfig(Clay_ElementConfigUnion config, Clay__ElementConfigType type) {
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
@ -2641,6 +2713,24 @@ Clay_String Clay__IntToString(int integer) {
return CLAY__INIT(Clay_String) { .length = length, .chars = chars };
}
typedef struct
{
Clay_String label;
Clay_Color color;
} Clay__DebugElementConfigTypeLabelConfig;
Clay__DebugElementConfigTypeLabelConfig Clay__DebugGetElementConfigTypeLabel(Clay__ElementConfigType type) {
switch (type) {
case CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Rectangle"), CLAY__INIT(Clay_Color) {243,134,48,255} };
case CLAY__ELEMENT_CONFIG_TYPE_TEXT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Text"), CLAY__INIT(Clay_Color) {105,210,231,255} };
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Image"), CLAY__INIT(Clay_Color) {121,189,154,255} };
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Floating"), CLAY__INIT(Clay_Color) {250,105,0,255} };
case CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Scroll"), CLAY__INIT(Clay_Color) {242,196,90,255} };
case CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Border"), CLAY__INIT(Clay_Color) {108,91,123, 255} };
case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Custom"), CLAY__INIT(Clay_Color) {11,72,107,255} };
}
}
typedef struct
{
uint32_t rowCount;
@ -2680,7 +2770,7 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
}
if (highlightedRowIndex == layoutData.rowCount) {
if (Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED_THIS_FRAME) {
if (Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
Clay__debugSelectedElementId = currentElement->id;
}
highlightedElementId = currentElement->id;
@ -2724,24 +2814,17 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
}
}
}
CLAY_TEXT(Clay__layoutElementIdStrings.internalArray[currentElementIndex], offscreen ? CLAY_TEXT_CONFIG(.textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16) : &Clay__DebugView_TextNameConfig);
Clay_String idString = Clay__layoutElementIdStrings.internalArray[currentElementIndex];
if (idString.length > 0) {
CLAY_TEXT(idString, offscreen ? CLAY_TEXT_CONFIG(.textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16) : &Clay__DebugView_TextNameConfig);
}
for (int elementConfigIndex = 0; elementConfigIndex < currentElement->elementConfigs.length; ++elementConfigIndex) {
Clay_ElementConfig *elementConfig = Clay__ElementConfigArraySlice_Get(&currentElement->elementConfigs, elementConfigIndex);
Clay_String elementTypeName = CLAY__INIT(Clay_String){};
Clay_Color elementTypeColor = CLAY__INIT(Clay_Color){};
switch (elementConfig->type) {
case CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE: elementTypeName = CLAY_STRING("Rectangle"); elementTypeColor = (CLAY__INIT(Clay_Color) {243,134,48,255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_TEXT: elementTypeName = CLAY_STRING("Text"); elementTypeColor = (CLAY__INIT(Clay_Color) {105,210,231,255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: elementTypeName = CLAY_STRING("Image"); elementTypeColor = (CLAY__INIT(Clay_Color) {121,189,154,255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER: elementTypeName = CLAY_STRING("Floating"); elementTypeColor = (CLAY__INIT(Clay_Color) {250,105,0,255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER: elementTypeName = CLAY_STRING("Scroll"); elementTypeColor = (CLAY__INIT(Clay_Color) {242,196,90,255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER: elementTypeName = CLAY_STRING("Border"); elementTypeColor = (CLAY__INIT(Clay_Color) {108,91,123, 255}); break;
case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: elementTypeName = CLAY_STRING("Custom"); elementTypeColor = (CLAY__INIT(Clay_Color) {11,72,107,255}); break;
}
Clay_Color backgroundColor = elementTypeColor;
Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(elementConfig->type);
Clay_Color backgroundColor = config.color;
backgroundColor.a = 90;
CLAY(CLAY_LAYOUT(.padding = { 8, 2 }), CLAY_RECTANGLE(.color = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4)), CLAY_BORDER_OUTSIDE_RADIUS(1, elementTypeColor, 4)) {
CLAY_TEXT(elementTypeName, CLAY_TEXT_CONFIG(.textColor = offscreen ? CLAY__DEBUGVIEW_COLOR_3 : CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16));
CLAY(CLAY_LAYOUT(.padding = { 8, 2 }), CLAY_RECTANGLE(.color = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4)), CLAY_BORDER_OUTSIDE_RADIUS(1, config.color, 4)) {
CLAY_TEXT(config.label, CLAY_TEXT_CONFIG(.textColor = offscreen ? CLAY__DEBUGVIEW_COLOR_3 : CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16));
}
}
}
@ -2766,8 +2849,8 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
Clay__ElementPostConfiguration();
Clay__OpenElement();
CLAY_BORDER(.left = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 });
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED( CLAY__DEBUGVIEW_INDENT_WIDTH)}, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT })) {}
Clay__ElementPostConfiguration();
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED( CLAY__DEBUGVIEW_INDENT_WIDTH)}, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT })) {}
Clay__OpenElement();
CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM);
Clay__ElementPostConfiguration();
@ -2783,7 +2866,7 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
}
}
if (Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED_THIS_FRAME) {
if (Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
Clay_ElementId collapseButtonId = Clay__HashString(CLAY_STRING("Clay__DebugView_CollapseElement"), 0, 0);
if (Clay__pointerInfo.position.x > Clay__layoutDimensions.width - (float)Clay__debugViewWidth && Clay__pointerInfo.position.x < Clay__layoutDimensions.width && Clay__pointerInfo.position.y > 0 && Clay__pointerInfo.position.y < Clay__layoutDimensions.height) {
for (int i = (int)Clay__pointerOverIds.length - 1; i >= 0; i--) {
@ -2830,14 +2913,17 @@ void Clay__RenderDebugLayoutSizing(Clay_SizingAxis sizing, Clay_TextElementConfi
}
}
void Clay__RenderDebugViewElementConfigHeader(Clay_String elementId, Clay_String title) {
CLAY(CLAY_IDI("Clay__DebugViewElementConfigItemBorder", 1), CLAY_LAYOUT(.sizing = {.width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1)}), CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_3)) {}
CLAY(CLAY_ID("Clay__DebugViewElementConfigItemHeader"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER})) {
CLAY_TEXT(title, CLAY_TEXT_CONFIG(.textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE));
CLAY(CLAY_IDI("Clay__DebugViewElementConfigTitleSpacer", 1), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW() })) {}
void Clay__RenderDebugViewElementConfigHeader(Clay_String elementId, Clay__ElementConfigType type) {
Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(type);
Clay_Color backgroundColor = config.color;
backgroundColor.a = 90;
CLAY(CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER })) {
CLAY(CLAY_LAYOUT(.padding = { 8, 2 }), CLAY_RECTANGLE(.color = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4)), CLAY_BORDER_OUTSIDE_RADIUS(1, config.color, 4)) {
CLAY_TEXT(config.label, CLAY_TEXT_CONFIG(.textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16));
}
CLAY(CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW() })) {}
CLAY_TEXT(elementId, CLAY_TEXT_CONFIG(.textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE));
}
CLAY(CLAY_IDI("Clay__DebugViewElementConfigItemBorder", 2), CLAY_LAYOUT(.sizing = {.width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1)}), CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_3)) {}
}
void Clay__RenderDebugViewColor(Clay_Color color, Clay_TextElementConfig *textConfig) {
@ -2884,7 +2970,7 @@ void Clay__RenderDebugViewBorder(int index, Clay_Border border, Clay_TextElement
void Clay__RenderDebugView() {
Clay_ElementId closeButtonId = Clay__HashString(CLAY_STRING("Clay__DebugViewTopHeaderCloseButtonOuter"), 0, 0);
if (Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED_THIS_FRAME) {
if (Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
for (int i = 0; i < Clay__pointerOverIds.length; ++i) {
Clay_ElementId *elementId = Clay__ElementIdArray_Get(&Clay__pointerOverIds, i);
if (elementId->id == closeButtonId.id) {
@ -2954,20 +3040,26 @@ void Clay__RenderDebugView() {
CLAY(CLAY_LAYOUT(.sizing = {.width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1)}), CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_3)) {}
if (Clay__debugSelectedElementId != 0) {
Clay_LayoutElementHashMapItem *selectedItem = Clay__GetHashMapItem(Clay__debugSelectedElementId);
CLAY(CLAY_SCROLL(.vertical = true), CLAY_LAYOUT(.sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM), CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_2)) {
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER})) {
CLAY(
CLAY_SCROLL(.vertical = true),
CLAY_LAYOUT(.sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM),
CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_2),
CLAY_BORDER(.betweenChildren = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 })
) {
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER})) {
CLAY_TEXT(CLAY_STRING("Layout Config"), infoTextConfig);
CLAY(CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW() })) {}
CLAY_TEXT(selectedItem->elementId.stringId, infoTitleConfig);
if (selectedItem->elementId.offset != 0) {
CLAY_TEXT(CLAY_STRING(" ("), infoTitleConfig);
CLAY_TEXT(Clay__IntToString(selectedItem->elementId.offset), infoTitleConfig);
CLAY_TEXT(CLAY_STRING(")"), infoTitleConfig);
if (selectedItem->elementId.stringId.length != 0) {
CLAY_TEXT(selectedItem->elementId.stringId, infoTitleConfig);
if (selectedItem->elementId.offset != 0) {
CLAY_TEXT(CLAY_STRING(" ("), infoTitleConfig);
CLAY_TEXT(Clay__IntToString(selectedItem->elementId.offset), infoTitleConfig);
CLAY_TEXT(CLAY_STRING(")"), infoTitleConfig);
}
}
}
// Clay_LayoutConfig debug info
CLAY(CLAY_LAYOUT(.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(1)}), CLAY_RECTANGLE(.color = CLAY__DEBUGVIEW_COLOR_3)) {}
CLAY(CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .boundingBox
CLAY_TEXT(CLAY_STRING("Bounding Box"), infoTitleConfig);
CLAY() {
@ -3031,11 +3123,11 @@ void Clay__RenderDebugView() {
}
for (int elementConfigIndex = 0; elementConfigIndex < selectedItem->layoutElement->elementConfigs.length; ++elementConfigIndex) {
Clay_ElementConfig *elementConfig = Clay__ElementConfigArraySlice_Get(&selectedItem->layoutElement->elementConfigs, elementConfigIndex);
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, elementConfig->type);
switch (elementConfig->type) {
case CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE: {
Clay_RectangleElementConfig *rectangleConfig = elementConfig->config.rectangleElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Rectangle Element Config"));
CLAY(CLAY_ID("Clay__DebugViewElementInfoRectangleBody"), CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .color
CLAY_TEXT(CLAY_STRING("Color"), infoTitleConfig);
Clay__RenderDebugViewColor(rectangleConfig->color, infoTextConfig);
@ -3047,8 +3139,7 @@ void Clay__RenderDebugView() {
}
case CLAY__ELEMENT_CONFIG_TYPE_TEXT: {
Clay_TextElementConfig *textConfig = elementConfig->config.textElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Text Element Config"));
CLAY(CLAY_ID("Clay__DebugViewElementInfoRectangleBody"), CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .fontSize
CLAY_TEXT(CLAY_STRING("Font Size"), infoTitleConfig);
CLAY_TEXT(Clay__IntToString(textConfig->fontSize), infoTextConfig);
@ -3057,7 +3148,7 @@ void Clay__RenderDebugView() {
CLAY_TEXT(Clay__IntToString(textConfig->fontId), infoTextConfig);
// .lineHeight
CLAY_TEXT(CLAY_STRING("Line Height"), infoTitleConfig);
CLAY_TEXT(Clay__IntToString(textConfig->lineHeight), infoTextConfig);
CLAY_TEXT(textConfig->lineHeight == 0 ? CLAY_STRING("auto") : Clay__IntToString(textConfig->lineHeight), infoTextConfig);
// .letterSpacing
CLAY_TEXT(CLAY_STRING("Letter Spacing"), infoTitleConfig);
CLAY_TEXT(Clay__IntToString(textConfig->letterSpacing), infoTextConfig);
@ -3078,8 +3169,7 @@ void Clay__RenderDebugView() {
}
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: {
Clay_ImageElementConfig *imageConfig = elementConfig->config.imageElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Image Element Config"));
CLAY(CLAY_ID("Clay__DebugViewElementInfoImageBody"), CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_ID("Clay__DebugViewElementInfoImageBody"), CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .sourceDimensions
CLAY_TEXT(CLAY_STRING("Source Dimensions"), infoTitleConfig);
CLAY(CLAY_ID("Clay__DebugViewElementInfoImageDimensions"), CLAY_LAYOUT()) {
@ -3097,8 +3187,7 @@ void Clay__RenderDebugView() {
}
case CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER: {
Clay_ScrollElementConfig *scrollConfig = elementConfig->config.scrollElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Scroll Element Config"));
CLAY(CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .vertical
CLAY_TEXT(CLAY_STRING("Vertical"), infoTitleConfig);
CLAY_TEXT(scrollConfig->vertical ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig);
@ -3110,8 +3199,7 @@ void Clay__RenderDebugView() {
}
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER: {
Clay_FloatingElementConfig *floatingConfig = elementConfig->config.floatingElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Floating Element Config"));
CLAY(CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .offset
CLAY_TEXT(CLAY_STRING("Offset"), infoTitleConfig);
CLAY() {
@ -3142,8 +3230,7 @@ void Clay__RenderDebugView() {
}
case CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER: {
Clay_BorderElementConfig *borderConfig = elementConfig->config.borderElementConfig;
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Border Element Config"));
CLAY(CLAY_ID("Clay__DebugViewElementInfoBorderBody"), CLAY_LAYOUT(.padding = {8, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
CLAY(CLAY_ID("Clay__DebugViewElementInfoBorderBody"), CLAY_LAYOUT(.padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM)) {
// .left
CLAY_TEXT(CLAY_STRING("Left Border"), infoTitleConfig);
Clay__RenderDebugViewBorder(1, borderConfig->left, infoTextConfig);
@ -3166,7 +3253,6 @@ void Clay__RenderDebugView() {
break;
}
case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: {
Clay__RenderDebugViewElementConfigHeader(selectedItem->elementId.stringId, CLAY_STRING("Layout Element Config"));
break;
}
}
@ -3242,8 +3328,11 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
}
Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1));
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO I wish there was a way around this, maybe the fact that it's essentially a binary tree limits the cost, have to measure
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO think of a way around this, maybe the fact that it's essentially a binary tree limits the cost, but the worst case is not great
if (mapItem && Clay__PointIsInsideRect(position, mapItem->boundingBox)) {
if (mapItem->onHoverFunction) {
mapItem->onHoverFunction(mapItem->elementId, Clay__pointerInfo, mapItem->hoverFunctionUserData);
}
Clay__ElementIdArray_Add(&Clay__pointerOverIds, mapItem->elementId);
if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT)) {
dfsBuffer.length--;
@ -3260,16 +3349,16 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
}
if (isPointerDown) {
if (Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED_THIS_FRAME) {
Clay__pointerInfo.state = CLAY__POINTER_INFO_PRESSED;
} else if (Clay__pointerInfo.state != CLAY__POINTER_INFO_PRESSED) {
Clay__pointerInfo.state = CLAY__POINTER_INFO_PRESSED_THIS_FRAME;
if (Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
Clay__pointerInfo.state = CLAY_POINTER_INFO_PRESSED;
} else if (Clay__pointerInfo.state != CLAY_POINTER_INFO_PRESSED) {
Clay__pointerInfo.state = CLAY_POINTER_INFO_PRESSED_THIS_FRAME;
}
} else {
if (Clay__pointerInfo.state == CLAY__POINTER_INFO_RELEASED_THIS_FRAME) {
Clay__pointerInfo.state = CLAY__POINTER_INFO_RELEASED;
} else if (Clay__pointerInfo.state != CLAY__POINTER_INFO_RELEASED) {
Clay__pointerInfo.state = CLAY__POINTER_INFO_RELEASED_THIS_FRAME;
if (Clay__pointerInfo.state == CLAY_POINTER_INFO_RELEASED_THIS_FRAME) {
Clay__pointerInfo.state = CLAY_POINTER_INFO_RELEASED;
} else if (Clay__pointerInfo.state != CLAY_POINTER_INFO_RELEASED) {
Clay__pointerInfo.state = CLAY_POINTER_INFO_RELEASED_THIS_FRAME;
}
}
}
@ -3291,7 +3380,7 @@ void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions) {
CLAY_WASM_EXPORT("Clay_UpdateScrollContainers")
void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime) {
bool isPointerActive = enableDragScrolling && (Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED || Clay__pointerInfo.state == CLAY__POINTER_INFO_PRESSED_THIS_FRAME);
bool isPointerActive = enableDragScrolling && (Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED || Clay__pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME);
// Don't apply scroll events to ancestors of the inner element
int32_t highestPriorityElementIndex = -1;
Clay__ScrollContainerDataInternal *highestPriorityScrollData = CLAY__NULL;
@ -3437,6 +3526,30 @@ Clay_RenderCommandArray Clay_EndLayout()
return Clay__renderCommands;
}
bool Clay_Hovered() {
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
// If the element has no id attached at this point, we need to generate one
if (openLayoutElement->id == 0) {
Clay__GenerateIdForAnonymousElement(openLayoutElement);
}
for (int i = 0; i < Clay__pointerOverIds.length; ++i) {
if (Clay__ElementIdArray_Get(&Clay__pointerOverIds, i)->id == openLayoutElement->id) {
return true;
}
}
return false;
}
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerInfo pointerInfo, intptr_t userData), intptr_t userData) {
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
if (openLayoutElement->id == 0) {
Clay__GenerateIdForAnonymousElement(openLayoutElement);
}
Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(openLayoutElement->id);
hashMapItem->onHoverFunction = onHoverFunction;
hashMapItem->hoverFunctionUserData = userData;
}
CLAY_WASM_EXPORT("Clay_PointerOver")
bool Clay_PointerOver(Clay_ElementId elementId) { // TODO return priority for separating multiple results
for (int i = 0; i < Clay__pointerOverIds.length; ++i) {

View File

@ -322,11 +322,13 @@
let length = memoryDataView.getUint32(scratchSpaceAddress + 4, true);
let arrayOffset = memoryDataView.getUint32(scratchSpaceAddress + 8, true);
let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
let previousId = 0;
for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
let entireRenderCommandMemory = new Uint32Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
let parentElement = scissorStack[scissorStack.length - 1];
let element = null;
let isMultiConfigElement = previousId === renderCommand.id.value;
if (!elementCache[renderCommand.id.value]) {
let elementType = 'div';
switch (renderCommand.commandType.value) {
@ -357,7 +359,7 @@
let elementData = elementCache[renderCommand.id.value];
element = elementData.element;
if (Array.prototype.indexOf.call(parentElement.element.children, element) !== parentElement.nextElementIndex) {
if (!isMultiConfigElement && Array.prototype.indexOf.call(parentElement.element.children, element) !== parentElement.nextElementIndex) {
if (parentElement.nextElementIndex === 0) {
parentElement.element.insertAdjacentElement('afterbegin', element);
} else {
@ -367,8 +369,12 @@
elementData.exists = true;
// Don't get me started. Cheaper to compare the render command memory than to update HTML elements
let dirty = MemoryIsDifferent(elementData.previousMemoryCommand, entireRenderCommandMemory, renderCommandSize);
parentElement.nextElementIndex++;
let dirty = MemoryIsDifferent(elementData.previousMemoryCommand, entireRenderCommandMemory, renderCommandSize) && !isMultiConfigElement;
if (!isMultiConfigElement) {
parentElement.nextElementIndex++;
}
previousId = renderCommand.id.value;
elementData.previousMemoryCommand = entireRenderCommandMemory;
let offsetX = scissorStack.length > 0 ? scissorStack[scissorStack.length - 1].nextAllocation.x : 0;

View File

@ -6,7 +6,7 @@
double windowWidth = 1024, windowHeight = 768;
float modelPageOneZRotation = 0;
int ACTIVE_RENDERER_INDEX = 1;
uint32_t ACTIVE_RENDERER_INDEX = 0;
const uint32_t FONT_ID_BODY_16 = 0;
const uint32_t FONT_ID_TITLE_56 = 1;
@ -174,7 +174,7 @@ void HighPerformancePageDesktop(float lerpValue) {
CLAY_TEXT(CLAY_STRING("Simplify animations and reactive UI design by avoiding the standard performance hacks."), CLAY_TEXT_CONFIG(.fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT));
}
CLAY(CLAY_ID("PerformanceRightImageOuter"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER})) {
CLAY(CLAY_ID(""), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(400) }), CLAY_BORDER_ALL(.width = 2, .color = COLOR_LIGHT)) {
CLAY(CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(400) }), CLAY_BORDER_ALL(.width = 2, .color = COLOR_LIGHT)) {
CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_PERCENT(0.3f + 0.4f * lerpValue), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {32, 32}), CLAY_RECTANGLE(.color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue))) {
CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG(.fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT));
}
@ -208,22 +208,25 @@ void HighPerformancePageMobile(float lerpValue) {
}
}
void HandleRendererButtonInteraction(Clay_ElementId elementId, Clay_PointerInfo pointerInfo, intptr_t userData) {
if (pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
ACTIVE_RENDERER_INDEX = (uint32_t)userData;
}
}
void RendererButtonActive(Clay_String text) {
Clay_ElementId buttonId;
CLAY(buttonId = CLAY_ID_LOCAL("button"),
CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(300) }, .padding = {16, 16}),
CLAY_RECTANGLE(.color = Clay_PointerOver(buttonId) ? COLOR_RED_HOVER : COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(10))
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(300) }, .padding = {16, 16}),
CLAY_RECTANGLE(.color = Clay_Hovered() ? COLOR_RED_HOVER : COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(10))
) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT));
}
}
void RendererButtonInactive(Clay_String text) {
Clay_ElementId buttonId;
CLAY(buttonId = CLAY_ID_LOCAL("button"),
CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(300)}, .padding = {16, 16}),
void RendererButtonInactive(Clay_String text, size_t rendererIndex) {
CLAY(CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(300)}, .padding = {16, 16}),
CLAY_BORDER_OUTSIDE_RADIUS(2, COLOR_RED, 10),
CLAY_RECTANGLE(.color = Clay_PointerOver(buttonId) ? COLOR_LIGHT_HOVER : COLOR_LIGHT, .cornerRadius = CLAY_CORNER_RADIUS(10), .cursorPointer = true)
CLAY_RECTANGLE(.color = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT, .cornerRadius = CLAY_CORNER_RADIUS(10), .cursorPointer = true),
Clay_OnHover(HandleRendererButtonInteraction, rendererIndex)
) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED));
}
@ -244,9 +247,9 @@ void RendererPageDesktop() {
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(.max = 32) })) {}
if (ACTIVE_RENDERER_INDEX == 0) {
RendererButtonActive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"), 1);
} else {
RendererButtonInactive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("HTML Renderer"), 0);
RendererButtonActive(CLAY_STRING("Canvas Renderer"));
}
}
@ -268,9 +271,9 @@ void RendererPageMobile() {
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(.max = 32) })) {}
if (ACTIVE_RENDERER_INDEX == 0) {
RendererButtonActive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"), 1);
} else {
RendererButtonInactive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("HTML Renderer"), 0);
RendererButtonActive(CLAY_STRING("Canvas Renderer"));
}
}
@ -306,30 +309,28 @@ float animationLerpValue = -1.0f;
Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
Clay_BeginLayout();
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }), CLAY_RECTANGLE(.color = COLOR_LIGHT)) {
CLAY(CLAY_ID("Header"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(50) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .childGap = 24, .padding = { 32 })) {
CLAY(CLAY_ID("Header"), CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(50) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .childGap = 16, .padding = { 32 })) {
CLAY_TEXT(CLAY_STRING("Clay"), &headerTextConfig);
CLAY(CLAY_ID("Spacer"), CLAY_LAYOUT(.sizing = { .width = CLAY_SIZING_GROW() })) {}
if (!mobileScreen) {
CLAY(CLAY_ID("LinkExamplesOuter"), CLAY_RECTANGLE(.link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples"), .color = {0,0,0,0})) {
CLAY(CLAY_ID("LinkExamplesOuter"), CLAY_LAYOUT(.padding = {8}), CLAY_RECTANGLE(.link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples"), .color = {0,0,0,0})) {
CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255}));
}
CLAY(CLAY_ID("LinkDocsOuter"), CLAY_RECTANGLE(.link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md"), .color = {0,0,0,0})) {
CLAY(CLAY_ID("LinkDocsOuter"), CLAY_LAYOUT(.padding = {8}), CLAY_RECTANGLE(.link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md"), .color = {0,0,0,0})) {
CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255}));
}
}
Clay_ElementId discordButtonId;
CLAY(discordButtonId = CLAY_ID("HeaderButtonGithub"),
CLAY_LAYOUT(.padding = {16, 6}),
CLAY_RECTANGLE(.cornerRadius = CLAY_CORNER_RADIUS(10), .link = CLAY_STRING("https://discord.gg/b4FTWkxdvT"), .color = Clay_PointerOver(discordButtonId) ? COLOR_LIGHT_HOVER : COLOR_LIGHT),
CLAY(CLAY_LAYOUT(.padding = {16, 6}),
CLAY_RECTANGLE(
.cornerRadius = CLAY_CORNER_RADIUS(10),
.link = CLAY_STRING("https://discord.gg/b4FTWkxdvT"),
.color = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT),
CLAY_BORDER_OUTSIDE_RADIUS(2, COLOR_RED, 10)
) {
CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255}));
}
Clay_ElementId githubButtonId;
CLAY(githubButtonId = CLAY_ID("HeaderButtonGithub"),
CLAY_LAYOUT(.padding = {16, 6}),
CLAY_RECTANGLE(.cornerRadius = CLAY_CORNER_RADIUS(10), .link = CLAY_STRING("https://github.com/nicbarker/clay"), .color = Clay_PointerOver(githubButtonId) ? COLOR_LIGHT_HOVER : COLOR_LIGHT),
CLAY(CLAY_LAYOUT(.padding = {16, 6}),
CLAY_RECTANGLE(.cornerRadius = CLAY_CORNER_RADIUS(10), .link = CLAY_STRING("https://github.com/nicbarker/clay"), .color = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT),
CLAY_BORDER_OUTSIDE_RADIUS(2, COLOR_RED, 10)
) {
CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG(.disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255}));
@ -343,7 +344,6 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
CLAY(CLAY_ID("OuterScrollContainer"),
CLAY_LAYOUT(.sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM),
CLAY_SCROLL(.vertical = true),
CLAY_RECTANGLE(.color = COLOR_LIGHT),
CLAY_BORDER(.betweenChildren = {2, COLOR_RED})
) {
if (mobileScreen) {
@ -364,16 +364,16 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
}
if (!mobileScreen) {
Clay_ScrollContainerData scrollData = Clay_GetScrollContainerData(CLAY_ID("OuterScrollContainer"));
Clay_ScrollContainerData scrollData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
Clay_Color scrollbarColor = (Clay_Color){225, 138, 50, 120};
if (scrollbarData.mouseDown) {
scrollbarColor = (Clay_Color){225, 138, 50, 200};
} else if (Clay_PointerOver(CLAY_ID("ScrollBar"))) {
} else if (Clay_PointerOver(Clay_GetElementId(CLAY_STRING("ScrollBar")))) {
scrollbarColor = (Clay_Color){225, 138, 50, 160};
}
float scrollHeight = scrollData.scrollContainerDimensions.height - 12;
CLAY(CLAY_ID("ScrollBar"),
CLAY_FLOATING(.offset = { .x = -6, .y = -(scrollData.scrollPosition->y / scrollData.contentDimensions.height) * scrollHeight + 6}, .zIndex = 1, .parentId = CLAY_ID("OuterScrollContainer").id, .attachment = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP}),
CLAY_FLOATING(.offset = { .x = -6, .y = -(scrollData.scrollPosition->y / scrollData.contentDimensions.height) * scrollHeight + 6}, .zIndex = 1, .parentId = Clay_GetElementId(CLAY_STRING("OuterScrollContainer")).id, .attachment = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP}),
CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(10), CLAY_SIZING_FIXED((scrollHeight / scrollData.contentDimensions.height) * scrollHeight)}),
CLAY_RECTANGLE(.cornerRadius = CLAY_CORNER_RADIUS(5), .color = scrollbarColor)
) {}
@ -399,14 +399,6 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
Clay_SetDebugModeEnabled(debugModeEnabled);
}
if (isTouchDown || isMouseDown) {
if (Clay_PointerOver(CLAY_ID("RendererSelectButtonHTML"))) {
ACTIVE_RENDERER_INDEX = 0;
} else if (Clay_PointerOver(CLAY_ID("RendererSelectButtonCanvas"))) {
ACTIVE_RENDERER_INDEX = 1;
}
}
Clay__debugViewHighlightColor = (Clay_Color) {105,210,231, 120};
Clay_SetPointerState((Clay_Vector2) {mousePositionX, mousePositionY}, isMouseDown || isTouchDown);
@ -415,13 +407,13 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
scrollbarData.mouseDown = false;
}
if (isMouseDown && !scrollbarData.mouseDown && Clay_PointerOver(CLAY_ID("ScrollBar"))) {
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(CLAY_ID("OuterScrollContainer"));
if (isMouseDown && !scrollbarData.mouseDown && Clay_PointerOver(Clay_GetElementId(CLAY_STRING("ScrollBar")))) {
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
scrollbarData.clickOrigin = (Clay_Vector2) { mousePositionX, mousePositionY };
scrollbarData.positionOrigin = *scrollContainerData.scrollPosition;
scrollbarData.mouseDown = true;
} else if (scrollbarData.mouseDown) {
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(CLAY_ID("OuterScrollContainer"));
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
if (scrollContainerData.contentDimensions.height > 0) {
Clay_Vector2 ratio = (Clay_Vector2) {
scrollContainerData.contentDimensions.width / scrollContainerData.scrollContainerDimensions.width,
@ -437,12 +429,12 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
}
if (arrowKeyDownPressedThisFrame) {
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(CLAY_ID("OuterScrollContainer"));
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
if (scrollContainerData.contentDimensions.height > 0) {
scrollContainerData.scrollPosition->y = scrollContainerData.scrollPosition->y - 50;
}
} else if (arrowKeyUpPressedThisFrame) {
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(CLAY_ID("OuterScrollContainer"));
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
if (scrollContainerData.contentDimensions.height > 0) {
scrollContainerData.scrollPosition->y = scrollContainerData.scrollPosition->y + 50;
}

View File

@ -20,7 +20,7 @@ FetchContent_MakeAvailable(raylib)
add_executable(clay_examples_raylib_sidebar_scrolling_container main.c multi-compilation-unit.c)
target_compile_options(clay_examples_raylib_sidebar_scrolling_container PUBLIC -Wall -Werror -Wno-unknown-pragmas)
target_compile_options(clay_examples_raylib_sidebar_scrolling_container PUBLIC -DCLAY_DEBUG -DCLAY_OVERFLOW_TRAP -Wall -Werror -Wno-unknown-pragmas)
target_include_directories(clay_examples_raylib_sidebar_scrolling_container PUBLIC .)
target_link_libraries(clay_examples_raylib_sidebar_scrolling_container PUBLIC raylib)

View File

@ -13,10 +13,17 @@ Texture2D profilePicture;
Clay_String profileText = CLAY_STRING("Profile Page one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen");
Clay_TextElementConfig headerTextConfig = (Clay_TextElementConfig) { .fontId = 1, .fontSize = 16, .textColor = {0,0,0,255} };
void HandleHeaderButtonInteraction(Clay_ElementId elementId, Clay_PointerInfo pointerInfo, intptr_t userData) {
if (pointerInfo.state == CLAY_POINTER_INFO_PRESSED_THIS_FRAME) {
return;
}
}
// Examples of re-usable "Components"
void RenderHeaderButton(uint16_t index, Clay_String text) {
Clay_ElementId buttonId = Clay__HashString(CLAY_STRING("HeaderButton"), index, 0);
CLAY(Clay__AttachId(buttonId), CLAY_LAYOUT(.padding = {16, 8}), CLAY_RECTANGLE(.color = Clay_PointerOver(buttonId) ? COLOR_BLUE : COLOR_ORANGE)) {
void RenderHeaderButton(Clay_String text) {
CLAY(CLAY_LAYOUT(.padding = {16, 8}),
CLAY_RECTANGLE(.color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE),
Clay_OnHover(HandleHeaderButtonInteraction, 1)) {
CLAY_TEXT(text, &headerTextConfig);
}
}
@ -33,6 +40,14 @@ void RenderDropdownTextItem(int index) {
Clay_RenderCommandArray CreateLayout() {
Clay_BeginLayout();
// CLAY(CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16), CLAY_BORDER(.betweenChildren = {1, {0,250,0,255}})) {
// CLAY(CLAY_RECTANGLE(.color = {150,0,0,255}), CLAY_LAYOUT(.childAlignment = { .y = CLAY_ALIGN_Y_CENTER })) {
// CLAY_TEXT(CLAY_STRING("TEST"), CLAY_TEXT_CONFIG(.fontSize = 60, .textColor = {255,255,255,255}));
// }
// CLAY(CLAY_RECTANGLE(.color = {150,0,0,255}), CLAY_LAYOUT(.childAlignment = { .y = CLAY_ALIGN_Y_CENTER })) {
// CLAY_TEXT(CLAY_STRING("TEST"), CLAY_TEXT_CONFIG(.fontSize = 60, .textColor = {255,255,255,255}));
// }
// }
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT(.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }, .padding = { 16, 16 }, .childGap = 16), CLAY_RECTANGLE(.color = {200, 200, 200, 255})) {
CLAY(CLAY_ID("SideBar"), CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16), CLAY_RECTANGLE(.color = {150, 150, 255, 255})) {
CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT(.sizing = { .width = CLAY_SIZING_GROW() }, .padding = { 8, 8 }, .childGap = 8, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }), CLAY_RECTANGLE(.color = {130, 130, 255, 255})) {
@ -47,9 +62,9 @@ Clay_RenderCommandArray CreateLayout() {
//
CLAY(CLAY_ID("RightPanel"), CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }, .childGap = 16)) {
CLAY(CLAY_ID("HeaderBar"), CLAY_LAYOUT(.sizing = { .width = CLAY_SIZING_GROW() }, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT }, .padding = {8, 8}, .childGap = 8), CLAY_RECTANGLE(.color = {180, 180, 180, 255})) {
RenderHeaderButton(1, CLAY_STRING("Header Item 1"));
RenderHeaderButton(2, CLAY_STRING("Header Item 2"));
RenderHeaderButton(3, CLAY_STRING("Header Item 3"));
RenderHeaderButton(CLAY_STRING("Header Item 1"));
RenderHeaderButton(CLAY_STRING("Header Item 2"));
RenderHeaderButton(CLAY_STRING("Header Item 3"));
}
CLAY(CLAY_ID("MainContent"),
CLAY_SCROLL(.vertical = true),
@ -110,9 +125,9 @@ Clay_RenderCommandArray CreateLayout() {
}
Clay_ScrollContainerData scrollData = Clay_GetScrollContainerData(Clay__HashString(CLAY_STRING("MainContent"), 0, 0));
if (scrollData.found) {
CLAY(CLAY_ID("ScrollBar"),CLAY_FLOATING(.offset = { .y = -(scrollData.scrollPosition->y / scrollData.contentDimensions.height) * scrollData.scrollContainerDimensions.height }, .zIndex = 1, .parentId = Clay__HashString(CLAY_STRING("MainContent"), 0, 0).id, .attachment = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP})) {
CLAY(CLAY_ID("ScrollBarButton"), CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(12), CLAY_SIZING_FIXED((scrollData.scrollContainerDimensions.height / scrollData.contentDimensions.height) * scrollData.scrollContainerDimensions.height)}), CLAY_RECTANGLE(.cornerRadius = {6}, .color = Clay_PointerOver(Clay__HashString(CLAY_STRING("ScrollBar"), 0, 0)) ? (Clay_Color){100, 100, 140, 150} : (Clay_Color){120, 120, 160, 150})) {}
};
CLAY(CLAY_ID("ScrollBar"),CLAY_FLOATING(.offset = { .y = -(scrollData.scrollPosition->y / scrollData.contentDimensions.height) * scrollData.scrollContainerDimensions.height }, .zIndex = 1, .parentId = Clay__HashString(CLAY_STRING("MainContent"), 0, 0).id, .attachment = {.element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP})) {
CLAY(CLAY_ID("ScrollBarButton"), CLAY_LAYOUT(.sizing = {CLAY_SIZING_FIXED(12), CLAY_SIZING_FIXED((scrollData.scrollContainerDimensions.height / scrollData.contentDimensions.height) * scrollData.scrollContainerDimensions.height)}), CLAY_RECTANGLE(.cornerRadius = {6}, .color = Clay_PointerOver(Clay__HashString(CLAY_STRING("ScrollBar"), 0, 0)) ? (Clay_Color){100, 100, 140, 150} : (Clay_Color){120, 120, 160, 150})) {}
};
}
};
return Clay_EndLayout();