Merge branch 'main' into feature/get-pointer

# Conflicts:
#	clay.h
This commit is contained in:
Orcolom 2025-02-26 21:12:35 +01:00
commit 0eb162e3a3
4 changed files with 174 additions and 106 deletions

View File

@ -475,6 +475,7 @@ Clay supports C preprocessor directives to modulate functionality at compile tim
The supported directives are:
- `CLAY_WASM` - Required when targeting Web Assembly.
- `CLAY_DLL` - Required when creating a .Dll file.
### Bindings for non C

View File

@ -1,6 +1,6 @@
### Odin Language Bindings
This directory contains bindings for the [Odin](odin-lang.org) programming language, as well as an example implementation of the [clay website](https://nicbarker.com/clay) in Odin.
This directory contains bindings for the [Odin](odin-lang.org) programming language, as well as an example implementation of the [Clay website](https://nicbarker.com/clay) in Odin.
Special thanks to
@ -8,21 +8,21 @@ Special thanks to
- [Dudejoe870](https://github.com/Dudejoe870)
- MrStevns from the Odin Discord server
If you haven't taken a look at the [full documentation for clay](https://github.com/nicbarker/clay/blob/main/README.md), it's recommended that you take a look there first to familiarise yourself with the general concepts. This README is abbreviated and applies to using clay in Odin specifically.
The **most notable difference** between the C API and the Odin bindings is the use of if statements to create the scope for declaring child elements. When using the equivalent of the [Element Macros](https://github.com/nicbarker/clay/blob/main/README.md#element-macros):
If you haven't taken a look at the [full documentation for Clay](https://github.com/nicbarker/clay/blob/main/README.md), it's recommended that you take a look there first to familiarise yourself with the general concepts. This README is abbreviated and applies to using Clay in Odin specifically.
The **most notable difference** between the C API and the Odin bindings is the use of `if` statements to create the scope for declaring child elements, when using the equivalent of the [Element Macros](https://github.com/nicbarker/clay/blob/main/README.md#element-macros):
```C
// C form of element macros
CLAY_RECTANGLE(CLAY_ID("SideBar"), CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW() }, .padding = {16, 16}), CLAY_RECTANGLE_CONFIG(.color = COLOR_LIGHT), {
// Child elements here
});
// Define an element with 16px of x and y padding
CLAY({ .id = CLAY_ID("Outer"), .layout = { .padding = CLAY_PADDING_ALL(16) } }) {
// Child elements here
}
```
```Odin
// Odin form of element macros
if clay.Rectangle(clay.ID("SideBar"), clay.Layout({ layoutDirection = .TOP_TO_BOTTOM, sizing = { width = clay.SizingFixed(300), height = clay.SizingGrow({}) }, padding = {16, 16} }), clay.RectangleConfig({ color = COLOR_LIGHT })) {
// Child elements here
if clay.UI()({ id = clay.ID("Outer"), layout = { padding = clay.PaddingAll(16) }}) {
// Child elements here
}
```
@ -34,111 +34,170 @@ if clay.Rectangle(clay.ID("SideBar"), clay.Layout({ layoutDirection = .TOP_TO_BO
import clay "clay-odin"
```
2. Ask clay for how much static memory it needs using [clay.MinMemorySize()](https://github.com/nicbarker/clay/blob/main/README.md#clay_minmemorysize), create an Arena for it to use with [clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)](https://github.com/nicbarker/clay/blob/main/README.md#clay_createarenawithcapacityandmemory), and initialize it with [clay.Initialize(arena)](https://github.com/nicbarker/clay/blob/main/README.md#clay_initialize).
2. Ask Clay for how much static memory it needs using [clay.MinMemorySize()](https://github.com/nicbarker/clay/blob/main/README.md#clay_minmemorysize), create an Arena for it to use with [clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)](https://github.com/nicbarker/clay/blob/main/README.md#clay_createarenawithcapacityandmemory), and initialize it with [clay.Initialize(clay.Arena, clay.Dimensions, clay.ErrorHandler)](https://github.com/nicbarker/clay/blob/main/README.md#clay_initialize).
```Odin
minMemorySize: u32 = clay.MinMemorySize()
memory := make([^]u8, minMemorySize)
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
clay.Initialize(arena)
error_handler :: proc "c" (errorData: clay.ErrorData) {
// Do something with the error data.
}
min_memory_size: u32 = clay.MinMemorySize()
memory := make([^]u8, min_memory_size)
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(min_memory_size, memory)
clay.Initialize(arena, { width = 1080, height = 720 }, { handler = error_handler })
```
3. Provide a `measureText(text, config)` proc "c" with [clay.SetMeasureTextFunction(function)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setmeasuretextfunction) so that clay can measure and wrap text.
3. Provide a `measure_text(text, config)` proc "c" with [clay.SetMeasureTextFunction(function)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setmeasuretextfunction) so that Clay can measure and wrap text.
```Odin
// Example measure text function
measureText :: proc "c" (text: ^clay.String, config: ^clay.TextElementConfig) -> clay.Dimensions {
// clay.TextElementConfig contains members such as fontId, fontSize, letterSpacing etc
measure_text :: proc "c" (
text: clay.StringSlice,
config: ^clay.TextElementConfig,
userData: rawptr,
) -> clay.Dimensions {
// clay.TextElementConfig contains members such as fontId, fontSize, letterSpacing, etc..
// Note: clay.String->chars is not guaranteed to be null terminated
return {
width = f32(text.length * i32(config.fontSize)),
height = f32(config.fontSize),
}
}
// Tell clay how to measure text
clay.SetMeasureTextFunction(measureText)
```
4. **Optional** - Call [clay.SetPointerPosition(pointerPosition)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setpointerposition) if you want to use mouse interactions.
// Tell clay how to measure text
clay.SetMeasureTextFunction(measure_text, nil)
```
4. **Optional** - Call [clay.SetPointerState(pointerPosition, isPointerDown)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setpointerstate) if you want to use mouse interactions.
```Odin
// Update internal pointer position for handling mouseover / click / touch events
clay.SetPointerPosition(clay.Vector2{ mousePositionX, mousePositionY })
clay.SetPointerState(
clay.Vector2 { mouse_pos_x, mouse_pos_y },
is_mouse_down,
)
```
5. Call [clay.BeginLayout(screenWidth, screenHeight)](https://github.com/nicbarker/clay/blob/main/README.md#clay_beginlayout) and declare your layout using the provided macros.
5. Call [clay.BeginLayout()](https://github.com/nicbarker/clay/blob/main/README.md#clay_beginlayout) and declare your layout using the provided macros.
```Odin
// Define some colors.
COLOR_LIGHT :: clay.Color{224, 215, 210, 255}
COLOR_RED :: clay.Color{168, 66, 28, 255}
COLOR_ORANGE :: clay.Color{225, 138, 50, 255}
COLOR_BLACK :: clay.Color{0, 0, 0, 255}
// Layout config is just a struct that can be declared statically, or inline
sidebarItemLayout := clay.LayoutConfig {
sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(50)},
sidebar_item_layout := clay.LayoutConfig {
sizing = {
width = clay.SizingGrow({}),
height = clay.SizingFixed(50)
},
}
// Re-useable components are just normal functions
SidebarItemComponent :: proc(index: u32) {
if clay.Rectangle(clay.ID("SidebarBlob", index), &sidebarItemLayout, clay.RectangleConfig({color = COLOR_ORANGE})) {}
// Re-useable components are just normal procs.
sidebar_item_component :: proc(index: u32) {
if clay.UI()({
id = clay.ID("SidebarBlob", index),
layout = sidebar_item_layout,
backgroundColor = COLOR_ORANGE,
}) {}
}
// An example function to begin the "root" of your layout tree
CreateLayout :: proc() -> clay.ClayArray(clay.RenderCommand) {
clay.BeginLayout(windowWidth, windowHeight)
// An example function to create your layout tree
create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
// Begin constructing the layout.
clay.BeginLayout()
// An example of laying out a UI with a fixed width sidebar and flexible width main content
// NOTE: To create a scope for child components, the Odin api uses `if` with components that have children
if clay.Rectangle(
clay.ID("OuterContainer"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
clay.RectangleConfig({color = {250, 250, 255, 255}}),
) {
if clay.Rectangle(
clay.ID("SideBar"),
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = clay.SizingFixed(300), height = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
clay.RectangleConfig({color = COLOR_LIGHT}),
) {
if clay.Rectangle(
clay.ID("ProfilePictureOuter"),
clay.Layout({sizing = {width = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16, childAlignment = {y = .CENTER}}),
clay.RectangleConfig({color = COLOR_RED}),
) {
if clay.Image(
clay.ID("ProfilePicture"),
clay.Layout({sizing = {width = clay.SizingFixed(60), height = clay.SizingFixed(60)}}),
clay.ImageConfig({imageData = &profilePicture, sourceDimensions = {height = 60, width = 60}}),
) {}
clay.Text(clay.ID("ProfileTitle"), "Clay - UI Library", clay.TextConfig({fontSize = 24, textColor = {255, 255, 255, 255}}))
// An example of laying out a UI with a fixed-width sidebar and flexible-width main content
// NOTE: To create a scope for child components, the Odin API uses `if` with components that have children
if clay.UI()({
id = clay.ID("OuterContainer"),
layout = {
sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
padding = { 16, 16, 16, 16 },
childGap = 16,
},
backgroundColor = { 250, 250, 255, 255 },
}) {
if clay.UI()({
id = clay.ID("SideBar"),
layout = {
layoutDirection = .TopToBottom,
sizing = { width = clay.SizingFixed(300), height = clay.SizingGrow({}) },
padding = { 16, 16, 16, 16 },
childGap = 16,
},
backgroundColor = COLOR_LIGHT,
}) {
if clay.UI()({
id = clay.ID("ProfilePictureOuter"),
layout = {
sizing = { width = clay.SizingGrow({}) },
padding = { 16, 16, 16, 16 },
childGap = 16,
childAlignment = { y = .Center },
},
backgroundColor = COLOR_RED,
cornerRadius = { 6, 6, 6, 6 },
}) {
if clay.UI()({
id = clay.ID("ProfilePicture"),
layout = {
sizing = { width = clay.SizingFixed(60), height = clay.SizingFixed(60) },
},
image = {
imageData = &profile_picture,
sourceDimensions = {
width = 60,
height = 60,
},
},
}) {}
clay.Text(
"Clay - UI Library",
clay.TextConfig({ textColor = COLOR_BLACK, fontSize = 16 }),
)
}
// Standard Odin code like loops etc work inside components
for i in 0..<10 {
SidebarItemComponent(i)
// Standard Odin code like loops, etc. work inside components.
// Here we render 5 sidebar items.
for i in u32(0)..<5 {
sidebar_item_component(i)
}
}
if clay.Rectangle(
clay.ID("MainContent"),
clay.Layout({sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}}),
clay.RectangleConfig({color = COLOR_LIGHT}),
) {}
if clay.UI()({
id = clay.ID("MainContent"),
layout = {
sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
},
backgroundColor = COLOR_LIGHT,
}) {}
}
// ...
// Returns a list of render commands
render_commands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout()
return render_commands
}
```
6. Call [clay.EndLayout(screenWidth, screenHeight)](https://github.com/nicbarker/clay/blob/main/README.md#clay_endlayout) and process the resulting [clay.RenderCommandArray](https://github.com/nicbarker/clay/blob/main/README.md#clay_rendercommandarray) in your choice of renderer.
6. Call your layout proc and process the resulting [clay.ClayArray(clay.RenderCommand)](https://github.com/nicbarker/clay/blob/main/README.md#clay_rendercommandarray) in your choice of renderer.
```Odin
renderCommands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout(windowWidth, windowHeight)
render_commands := create_layout()
for i: u32 = 0; i < renderCommands.length; i += 1 {
renderCommand := clay.RenderCommandArray_Get(&renderCommands, cast(i32)i)
for i in 0..<i32(render_commands.length) {
render_command := clay.RenderCommandArray_Get(render_commands, i)
switch renderCommand.commandType {
switch render_command.commandType {
case .Rectangle:
DrawRectangle(renderCommand.boundingBox, renderCommand.config.rectangleElementConfig.color)
DrawRectangle(render_command.boundingBox, render_command.config.rectangleElementConfig.color)
// ... Implement handling of other command types
}
}
```
Please see the [full C documentation for clay](https://github.com/nicbarker/clay/blob/main/README.md) for API details. All public C functions and Macros have Odin binding equivalents, generally of the form `CLAY_RECTANGLE` (C) -> `clay.Rectangle` (Odin)
Please see the [full C documentation for Clay](https://github.com/nicbarker/clay/blob/main/README.md) for API details. All public C functions and Macros have Odin binding equivalents, generally of the form `CLAY_ID` (C) -> `clay.ID` (Odin).

78
clay.h
View File

@ -42,6 +42,12 @@
#define CLAY_WASM_EXPORT(null)
#endif
#ifdef CLAY_DLL
#define CLAY_DLL_EXPORT __declspec(dllexport) __stdcall
#else
#define CLAY_DLL_EXPORT
#endif
// Public Macro API ------------------------
#define CLAY__MAX(x, y) (((x) > (y)) ? (x) : (y))
@ -769,12 +775,12 @@ typedef struct {
// Public API functions ------------------------------------------
// Returns the size, in bytes, of the minimum amount of memory Clay requires to operate at its current settings.
uint32_t Clay_MinMemorySize(void);
CLAY_DLL_EXPORT uint32_t Clay_MinMemorySize(void);
// Creates an arena for clay to use for its internal allocations, given a certain capacity in bytes and a pointer to an allocation of at least that size.
// Intended to be used with Clay_MinMemorySize in the following way:
// uint32_t minMemoryRequired = Clay_MinMemorySize();
// Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(minMemoryRequired, malloc(minMemoryRequired));
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *memory);
CLAY_DLL_EXPORT Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *memory);
// 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.
void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
@ -785,89 +791,89 @@ Clay_PointerData Clay_GetPointerState();
// - 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)
// - errorHandler is used by Clay to inform you if something has gone wrong in configuration or layout.
Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
CLAY_DLL_EXPORT Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
// Returns the Context that clay is currently using. Used when using multiple instances of clay simultaneously.
Clay_Context* Clay_GetCurrentContext(void);
CLAY_DLL_EXPORT Clay_Context* Clay_GetCurrentContext(void);
// Sets the context that clay will use to compute the layout.
// Used to restore a context saved from Clay_GetCurrentContext when using multiple instances of clay simultaneously.
void Clay_SetCurrentContext(Clay_Context* context);
CLAY_DLL_EXPORT void Clay_SetCurrentContext(Clay_Context* context);
// Updates the state of Clay's internal scroll data, updating scroll content positions if scrollDelta is non zero, and progressing momentum scrolling.
// - enableDragScrolling when set to true will enable mobile device like "touch drag" scroll of scroll containers, including momentum scrolling after the touch has ended.
// - scrollDelta is the amount to scroll this frame on each axis in pixels.
// - deltaTime is the time in seconds since the last "frame" (scroll update)
void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
CLAY_DLL_EXPORT void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
// Updates the layout dimensions in response to the window or outer container being resized.
void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
CLAY_DLL_EXPORT void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
// Called before starting any layout declarations.
void Clay_BeginLayout(void);
CLAY_DLL_EXPORT void Clay_BeginLayout(void);
// Called when all layout declarations are finished.
// Computes the layout and generates and returns the array of render commands to draw.
Clay_RenderCommandArray Clay_EndLayout(void);
CLAY_DLL_EXPORT Clay_RenderCommandArray Clay_EndLayout(void);
// Calculates a hash ID from the given idString.
// Generally only used for dynamic strings when CLAY_ID("stringLiteral") can't be used.
Clay_ElementId Clay_GetElementId(Clay_String idString);
CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementId(Clay_String idString);
// Calculates a hash ID from the given idString and index.
// - index is used to avoid constructing dynamic ID strings in loops.
// Generally only used for dynamic strings when CLAY_IDI("stringLiteral", index) can't be used.
Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index);
CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index);
// Returns layout data such as the final calculated bounding box for an element with a given ID.
// The returned Clay_ElementData contains a `found` bool that will be true if an element with the provided ID was found.
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
Clay_ElementData Clay_GetElementData(Clay_ElementId id);
CLAY_DLL_EXPORT Clay_ElementData Clay_GetElementData(Clay_ElementId id);
// Returns true if the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
// Works during element declaration, e.g. CLAY({ .backgroundColor = Clay_Hovered() ? BLUE : RED });
bool Clay_Hovered(void);
CLAY_DLL_EXPORT bool Clay_Hovered(void);
// Bind a callback that will be called when the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
// - onHoverFunction is a function pointer to a user defined function.
// - userData is a pointer that will be transparently passed through when the onHoverFunction is called.
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData);
CLAY_DLL_EXPORT void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData);
// An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
bool Clay_PointerOver(Clay_ElementId elementId);
CLAY_DLL_EXPORT bool Clay_PointerOver(Clay_ElementId elementId);
// Returns data representing the state of the scrolling element with the provided ID.
// The returned Clay_ScrollContainerData contains a `found` bool that will be true if a scroll element was found with the provided ID.
// An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
CLAY_DLL_EXPORT Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
// Binds a callback function that Clay will call to determine the dimensions of a given string slice.
// - measureTextFunction is a user provided function that adheres to the interface Clay_Dimensions (Clay_StringSlice text, Clay_TextElementConfig *config, void *userData);
// - userData is a pointer that will be transparently passed through when the measureTextFunction is called.
void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData);
CLAY_DLL_EXPORT void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData);
// Experimental - Used in cases where Clay needs to integrate with a system that manages its own scrolling containers externally.
// Please reach out if you plan to use this function, as it may be subject to change.
void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData);
CLAY_DLL_EXPORT void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData);
// A bounds-checked "get" function for the Clay_RenderCommandArray returned from Clay_EndLayout().
Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
CLAY_DLL_EXPORT Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
// Enables and disables Clay's internal debug tools.
// This state is retained and does not need to be set each frame.
void Clay_SetDebugModeEnabled(bool enabled);
CLAY_DLL_EXPORT void Clay_SetDebugModeEnabled(bool enabled);
// Returns true if Clay's internal debug tools are currently enabled.
bool Clay_IsDebugModeEnabled(void);
CLAY_DLL_EXPORT bool Clay_IsDebugModeEnabled(void);
// Enables and disables visibility culling. By default, Clay will not generate render commands for elements whose bounding box is entirely outside the screen.
void Clay_SetCullingEnabled(bool enabled);
CLAY_DLL_EXPORT void Clay_SetCullingEnabled(bool enabled);
// Returns the maximum number of UI elements supported by Clay's current configuration.
int32_t Clay_GetMaxElementCount(void);
CLAY_DLL_EXPORT int32_t Clay_GetMaxElementCount(void);
// Modifies the maximum number of UI elements supported by Clay's current configuration.
// This may require reallocating additional memory, and re-calling Clay_Initialize();
void Clay_SetMaxElementCount(int32_t maxElementCount);
CLAY_DLL_EXPORT void Clay_SetMaxElementCount(int32_t maxElementCount);
// Returns the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
CLAY_DLL_EXPORT int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
// Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
// This may require reallocating additional memory, and re-calling Clay_Initialize();
void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
// Resets Clay's internal text measurement cache, useful if memory to represent strings is being re-used.
// Similar behaviour can be achieved on an individual text element level by using Clay_TextElementConfig.hashStringContents
void Clay_ResetMeasureTextCache(void);
CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void);
// Internal API functions required by macros ----------------------
void Clay__OpenElement(void);
void Clay__ConfigureOpenElement(const Clay_ElementDeclaration config);
void Clay__CloseElement(void);
Clay_ElementId Clay__HashString(Clay_String key, uint32_t offset, uint32_t seed);
void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig);
Clay_TextElementConfig *Clay__StoreTextElementConfig(Clay_TextElementConfig config);
uint32_t Clay__GetParentElementId(void);
CLAY_DLL_EXPORT void Clay__OpenElement(void);
CLAY_DLL_EXPORT void Clay__ConfigureOpenElement(const Clay_ElementDeclaration config);
CLAY_DLL_EXPORT void Clay__CloseElement(void);
CLAY_DLL_EXPORT Clay_ElementId Clay__HashString(Clay_String key, uint32_t offset, uint32_t seed);
CLAY_DLL_EXPORT void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig);
CLAY_DLL_EXPORT Clay_TextElementConfig *Clay__StoreTextElementConfig(Clay_TextElementConfig config);
CLAY_DLL_EXPORT uint32_t Clay__GetParentElementId(void);
extern Clay_Color Clay__debugViewHighlightColor;
extern uint32_t Clay__debugViewWidth;
@ -3651,11 +3657,13 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&dfsBuffer, (int)dfsBuffer.length - 1));
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
int32_t clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, currentElement - context->layoutElements.internalArray);
Clay_LayoutElementHashMapItem *clipItem = Clay__GetHashMapItem(clipElementId);
Clay_BoundingBox elementBox = mapItem->boundingBox;
elementBox.x -= root->pointerOffset.x;
elementBox.y -= root->pointerOffset.y;
if (mapItem) {
if ((Clay__PointIsInsideRect(position, elementBox))) {
if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)))) {
if (mapItem->onHoverFunction) {
mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData);
}

View File

@ -80,7 +80,7 @@ Clay_RenderCommandArray CreateLayout(void) {
CLAY_TEXT(CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt."),
CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {0,0,0,255} }));
CLAY({ .id = CLAY_ID("Photos2"), .layout = { .childGap = 16, .padding = { 16, 16, 16, 16 }}, .backgroundColor = {180, 180, 220, 255} }) {
CLAY({ .id = CLAY_ID("Photos2"), .layout = { .childGap = 16, .padding = { 16, 16, 16, 16 }}, .backgroundColor = {180, 180, 220, Clay_Hovered() ? 120 : 255} }) {
CLAY({ .id = CLAY_ID("Picture4"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(120), .height = CLAY_SIZING_FIXED(120) }}, .image = { .imageData = &profilePicture, .sourceDimensions = {120, 120} }}) {}
CLAY({ .id = CLAY_ID("Picture5"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(120), .height = CLAY_SIZING_FIXED(120) }}, .image = { .imageData = &profilePicture, .sourceDimensions = {120, 120} }}) {}
CLAY({ .id = CLAY_ID("Picture6"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(120), .height = CLAY_SIZING_FIXED(120) }}, .image = { .imageData = &profilePicture, .sourceDimensions = {120, 120} }}) {}