diff --git a/.gitignore b/.gitignore index 1e77fce..0e9297b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ cmake-build-*/ +build/ .DS_Store .idea/ node_modules/ *.dSYM +.vs/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cfd1ca..8846873 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,13 +4,14 @@ project(clay) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") add_subdirectory("examples/cpp-project-example") - -# Don't try to compile C99 projects using MSVC +add_subdirectory("examples/raylib-multi-context") +add_subdirectory("examples/raylib-sidebar-scrolling-container") +# add_subdirectory("examples/cairo-pdf-rendering") Some issue with github actions populating cairo, disable for now if(NOT MSVC) - add_subdirectory("examples/raylib-sidebar-scrolling-container") - add_subdirectory("examples/cairo-pdf-rendering") add_subdirectory("examples/clay-official-website") add_subdirectory("examples/introducing-clay-video-demo") add_subdirectory("examples/SDL2-video-demo") add_subdirectory("examples/minimal-imgui") endif() +add_subdirectory("examples/introducing-clay-video-demo") +add_subdirectory("examples/SDL2-video-demo") diff --git a/README.md b/README.md index 2d19696..e87cdf7 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255}; // Layout config is just a struct that can be declared statically, or inline Clay_LayoutConfig sidebarItemLayout = (Clay_LayoutConfig) { - .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) }, + .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }, }; // Re-useable components are just normal functions @@ -94,13 +94,13 @@ Clay_RenderCommandArray CreateLayout() { Clay_BeginLayout(); // An example of laying out a UI with a fixed width sidebar and flexible width main content - CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_GROW()}, .padding = {16, 16}, .childGap = 16 }), CLAY_RECTANGLE({ .color = {250,250,255,255} })) { + CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .padding = {16, 16}, .childGap = 16 }), CLAY_RECTANGLE({ .color = {250,250,255,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_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW(0) }, .padding = {16, 16}, .childGap = 16 }), CLAY_RECTANGLE({ .color = COLOR_LIGHT }) ) { - CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }), CLAY_RECTANGLE({ .color = COLOR_RED })) { - CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}), CLAY_IMAGE({ .imageData = &profilePicture, .height = 60, .width = 60 })) {} + CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = {16, 16}, .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }), CLAY_RECTANGLE({ .color = COLOR_RED })) { + CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {} CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} })); } @@ -110,7 +110,7 @@ Clay_RenderCommandArray CreateLayout() { } } - CLAY(CLAY_ID("MainContent"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }}), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {} + CLAY(CLAY_ID("MainContent"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }}), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {} } // ... }); @@ -151,6 +151,62 @@ In summary, the general order of steps is: For help starting out or to discuss clay, considering joining [the discord server.](https://discord.gg/b4FTWkxdvT) +## Summary + +- [High Level Documentation](#high-level-documentation) + - [Building UI Hierarchies](#building-ui-hierarchies) + - [Configuring Layout and Styling UI Elements](#configuring-layout-and-styling-ui-elements) + - [Element IDs](#element-ids) + - [Mouse, Touch and Pointer Interactions](#mouse-touch-and-pointer-interactions) + - [Scrolling Elements](#scrolling-elements) + - [Floating Elements](#floating-elements-absolute-positioning) + - [Custom Elements](#laying-out-your-own-custom-elements) + - [Retained Mode Rendering](#retained-mode-rendering) + - [Visibility Culling](#visibility-culling) + - [Preprocessor Directives](#preprocessor-directives) + - [Bindings](#bindings-for-non-c) + - [Debug Tools](#debug-tools) +- [API](#api) + - [Naming Conventions](#naming-conventions) + - [Public Functions](#public-functions) + - [Lifecycle](#lifecycle-for-public-functions) + - [Clay_MinMemorySize](#clay_minmemorysize) + - [Clay_CreateArenaWithCapacityAndMemory](#clay_createarenawithcapacityandmemory) + - [Clay_SetMeasureTextFunction](#clay_setmeasuretextfunction) + - [Clay_SetMaxElementCount](clay_setmaxelementcount) + - [Clay_SetMaxMeasureTextCacheWordCount](#clay_setmaxmeasuretextcachewordcount) + - [Clay_Initialize](#clay_initialize) + - [Clay_SetLayoutDimensions](#clay_setlayoutdimensions) + - [Clay_SetPointerState](#clay_setpointerstate) + - [Clay_UpdateScrollContainers](#clay_updatescrollcontainers) + - [Clay_BeginLayout](#clay_beginlayout) + - [Clay_EndLayout](#clay_endlayout) + - [Clay_Hovered](#clay_hovered) + - [Clay_OnHover](#clay_onhover) + - [Clay_PointerOver](#clay_pointerover) + - [Clay_GetScrollContainerData](#clay_getscrollcontainerdata) + - [Clay_GetElementId](#clay_getelementid) + - [Element Macros](#element-macros) + - [CLAY](#clay-1) + - [CLAY_ID](#clay_id) + - [CLAY_IDI](#clay_idi) + - [CLAY_LAYOUT](#clay_layout) + - [CLAY_RECTANGLE](#clay_rectangle) + - [CLAY_TEXT](#clay_text) + - [CLAY_IMAGE](#clay_image) + - [CLAY_SCROLL](#clay_scroll) + - [CLAY_BORDER](#clay_border) + - [CLAY_FLOATING](#clay_floating) + - [CLAY_CUSTOM_ELEMENT](#clay_custom_element) + - [Data Structures & Defs](data-structures--definitions) + - [Clay_String](#clay_string) + - [Clay_ElementId](#clay_elementid) + - [Clay_RenderCommandArray](#clay_rendercommandarray) + - [Clay_RenderCommand](#clay_rendercommand) + - [Clay_ScrollContainerData](#clay_scrollcontainerdata) + - [Clay_ErrorHandler](#clay_errorhandler) + - [Clay_ErrorData](#clay_errordata) + ## High Level Documentation ### Building UI Hierarchies @@ -187,7 +243,7 @@ CLAY(CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM })) { } // Only render this element if we're on a mobile screen if (isMobileScreen) { - CLAY() { + CLAY(0) { // etc } } @@ -362,7 +418,7 @@ typedef struct t_CustomElementData { Model myModel = Load3DModel(filePath); CustomElement modelElement = (CustomElement) { .type = CUSTOM_ELEMENT_TYPE_MODEL, .model = myModel } // ... -CLAY() { +CLAY(0) { // This config is type safe and contains the CustomElementData struct CLAY(CLAY_CUSTOM_ELEMENT({ .customData = { .type = CUSTOM_ELEMENT_TYPE_MODEL, .model = myModel } })) {} } @@ -425,8 +481,7 @@ Clay is usable out of the box as a `.h` include in both C99 and C++20 with desig There are also supported bindings for other languages, including: - [Odin Bindings](https://github.com/nicbarker/clay/tree/main/bindings/odin) - -Unfortunately clay does **not** support Microsoft C11 or C17 via MSVC at this time. +- [Rust Bindings](https://github.com/clay-ui-rs/clay) ### Debug Tools @@ -442,6 +497,36 @@ The debug tooling by default will render as a panel to the right side of the scr _The official Clay website with debug tooling visible_ +### Running more than one Clay instance + +Clay allows you to run more than one instance in a program. To do this, [Clay_Initialize](#clay_initialize) returns a [Clay_Context*](#clay_context) reference. You can activate a specific instance using [Clay_SetCurrentContext](#clay_setcurrentcontext). If [Clay_SetCurrentContext](#clay_setcurrentcontext) is not called, then Clay will default to using the context from the most recently called [Clay_Initialize](#clay_initialize). + +**⚠ Important: Do not render instances across different threads simultaneously, as Clay does not currently support proper multi-threading.** + +```c++ +// Define separate arenas for the instances. +Clay_Arena arena1, arena2; +// ... allocate arenas + +// Initialize both instances, storing the context for each one. +Clay_Context* instance1 = Clay_Initialize(arena1, layoutDimensions, errorHandler); +Clay_Context* instance2 = Clay_Initialize(arena2, layoutDimensions, errorHandler); + +// In the program's render function, activate each instance before executing clay commands and macros. +Clay_SetCurrentContext(instance1); +Clay_BeginLayout(); +// ... declare layout for instance1 +Clay_RenderCommandArray renderCommands1 = Clay_EndLayout(); +render(renderCommands1); + +// Switch to the second instance +Clay_SetCurrentContext(instance2); +Clay_BeginLayout(); +// ... declare layout for instance2 +Clay_RenderCommandArray renderCommands2 = Clay_EndLayout(); +render(renderCommands2); +``` + # API ### Naming Conventions @@ -460,18 +545,24 @@ _The official Clay website with debug tooling visible_ **Each Frame** `Clay_SetLayoutDimensions` -> `Clay_SetPointerState` -> `Clay_UpdateScrollContainers` -> `Clay_BeginLayout` -> `CLAY() etc...` -> `Clay_EndLayout` +--- + ### Clay_MinMemorySize `uint32_t Clay_MinMemorySize()` Returns the minimum amount of memory **in bytes** that clay needs to accomodate the current [CLAY_MAX_ELEMENT_COUNT](#preprocessor-directives). +--- + ### Clay_CreateArenaWithCapacityAndMemory `Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset)` Creates a `Clay_Arena` struct with the given capacity and base memory pointer, which can be passed to [Clay_Initialize](#clay_initialize). +--- + ### Clay_SetMeasureTextFunction `void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config))` @@ -482,29 +573,49 @@ Takes a pointer to a function that can be used to measure the `width, height` di **Note 2: It is essential that this function is as fast as possible.** For text heavy use-cases this function is called many times, and despite the fact that clay caches text measurements internally, it can easily become the dominant overall layout cost if the provided function is slow. **This is on the hot path!** +--- + ### Clay_SetMaxElementCount `void Clay_SetMaxElementCount(uint32_t maxElementCount)` -Updates the internal maximum element count, allowing clay to allocate larger UI hierarchies. +Sets the internal maximum element count that will be used in subsequent [Clay_Initialize()](#clay_initialize) and [Clay_MinMemorySize()](#clay_minmemorysize) calls, allowing clay to allocate larger UI hierarchies. **Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.** +--- + ### Clay_SetMaxMeasureTextCacheWordCount `void Clay_SetMaxMeasureTextCacheWordCount(uint32_t maxMeasureTextCacheWordCount)` -Updates the internal text measurement cache size, allowing clay to allocate more text. The value represents how many seperate words can be stored in the text measurement cache. +Sets the internal text measurement cache size that will be used in subsequent [Clay_Initialize()](#clay_initialize) and [Clay_MinMemorySize()](#clay_minmemorysize) calls, allowing clay to allocate more text. The value represents how many separate words can be stored in the text measurement cache. **Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.** +--- + ### Clay_Initialize -`void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler)` +`Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler)` -Initializes the internal memory mapping, sets the internal dimensions for layout, and binds an error handler for clay to use when something goes wrong. +Initializes the internal memory mapping, sets the internal dimensions for layout, and binds an error handler for clay to use when something goes wrong. Returns a [Clay_Context*](#clay_context) that can optionally be given to [Clay_SetCurrentContext](#clay_setcurrentcontext) to allow running multiple instances of clay in the same program, and sets it as the current context. See [Running more than one Clay instance](#running-more-than-one-clay-instance). -Reference: [Clay_Arena](#clay_createarenawithcapacityandmemory), [Clay_ErrorHandler](#clay_errorhandler) +Reference: [Clay_Arena](#clay_createarenawithcapacityandmemory), [Clay_ErrorHandler](#clay_errorhandler), [Clay_SetCurrentContext](#clay_setcurrentcontext) + +### Clay_SetCurrentContext + +`void Clay_SetCurrentContext(Clay_Context* context)` + +Sets the context that subsequent clay commands will operate on. You can get this reference from [Clay_Initialize](#clay_initialize) or [Clay_GetCurrentContext](#clay_getcurrentcontext). See [Running more than one Clay instance](#running-more-than-one-clay-instance). + +### Clay_GetCurrentContext + +`Clay_Context* Clay_GetCurrentContext()` + +Returns the context that clay commands are currently operating on, or null if no context has been set. See [Running more than one Clay instance](#running-more-than-one-clay-instance). + +--- ### Clay_SetLayoutDimensions @@ -512,12 +623,16 @@ Reference: [Clay_Arena](#clay_createarenawithcapacityandmemory), [Clay_ErrorHand Sets the internal layout dimensions. Cheap enough to be called every frame with your screen dimensions to automatically respond to window resizing, etc. +--- + ### Clay_SetPointerState `void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown)` Sets the internal pointer position and state (i.e. current mouse / touch position) and recalculates overlap info, which is used for mouseover / click calculation (via [Clay_PointerOver](#clay_pointerover) and updating scroll containers with [Clay_UpdateScrollContainers](#clay_updatescrollcontainers). **isPointerDown should represent the current state this frame, e.g. it should be `true` for the entire duration the left mouse button is held down.** Clay has internal handling for detecting click / touch start & end. +--- + ### Clay_UpdateScrollContainers `void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime)` @@ -528,24 +643,32 @@ Touch / drag scrolling only occurs if the `enableDragScrolling` parameter is `tr `deltaTime` is the time **in seconds** since the last frame (e.g. 0.016 is **16 milliseconds**), and is used to normalize & smooth scrolling across different refresh rates. +--- + ### Clay_BeginLayout `void Clay_BeginLayout()` Prepares clay to calculate a new layout. Called each frame / layout **before** any of the [Element Macros](#element-macros). +--- + ### Clay_EndLayout `Clay_RenderCommandArray Clay_EndLayout()` Ends declaration of element macros and calculates the results of the current layout. Renders a [Clay_RenderCommandArray](#clay_rendercommandarray) containing the results of the layout calculation. +--- + ### Clay_Hovered `bool Clay_Hovered()` Called **during** layout declaration, and returns `true` if the pointer position previously set with `Clay_SetPointerState` is inside the bounding box of the currently open element. Note: this is based on the element's position from the **last** frame. +--- + ### Clay_OnHover `void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData)` @@ -570,6 +693,8 @@ CLAY(CLAY_LAYOUT({ .padding = { 8, 8 }}), Clay_OnHover(HandleButtonInteraction, } ``` +--- + ### Clay_PointerOver `bool Clay_PointerOver(Clay_ElementId id)` @@ -582,6 +707,8 @@ Returns `true` if the pointer position previously set with `Clay_SetPointerState Returns [Clay_ScrollContainerData](#clay_scrollcontainerdata) for the scroll container matching the provided ID. This function allows imperative manipulation of scroll position, allowing you to build things such as scroll bars, buttons that "jump" to somewhere in a scroll container, etc. +--- + ### Clay_GetElementId `Clay_ElementId Clay_GetElementId(Clay_String idString)` @@ -602,6 +729,7 @@ Returns a [Clay_ElementId](#clay_elementid) for the provided id string, used for **Notes** **CLAY** opens a generic empty container, that is configurable and supports nested children. +**CLAY** requires at least 1 parameter, so if you want to create an element without any configuration, use `CLAY(0)`. **Examples** ```C @@ -622,6 +750,8 @@ CLAY(CLAY_ID("Outer"), CLAY_LAYOUT({ .padding = {16, 16} })) { } ``` +--- + ### CLAY_ID **Usage** @@ -644,7 +774,7 @@ To regenerate the same ID outside of layout declaration when using utility funct // Tag a button with the Id "Button" CLAY( CLAY_ID("Button"), - CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16) }) + CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = {16, 16}, .childGap = 16) }) ) { // ...children } @@ -656,12 +786,16 @@ if (buttonIsHovered && leftMouseButtonPressed) { } ``` +--- + ### CLAY_IDI() `Clay_ElementId CLAY_IDI(char *label, int index)` An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime. +--- + ### CLAY_LAYOUT **Usage** @@ -691,8 +825,8 @@ Clay_LayoutConfig { .y = CLAY_ALIGN_Y_TOP (default) | CLAY_ALIGN_Y_CENTER | CLAY_ALIGN_Y_BOTTOM; }; Clay_Sizing sizing { // Recommended to use the provided macros here - see #sizing for more in depth explanation - .width = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(width) | CLAY_SIZING_PERCENT(float percent) - .height = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(height) | CLAY_SIZING_PERCENT(float percent) + .width = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(float width) | CLAY_SIZING_PERCENT(float percent) + .height = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(float height) | CLAY_SIZING_PERCENT(float percent) }; // See CLAY_SIZING_GROW() etc for more details }; ``` @@ -768,11 +902,13 @@ Controls how final width and height of element are calculated. The same configur **Example Usage** ```C -CLAY(CLAY_ID("Button"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16) }) { +CLAY(CLAY_ID("Button"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = {16, 16}, .childGap = 16) }) { // Children will be laid out vertically with 16px of padding around and between } ``` +--- + ### CLAY_RECTANGLE **Usage** @@ -854,6 +990,8 @@ CLAY( } ``` +--- + ### CLAY_TEXT **Usage** @@ -975,6 +1113,8 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_ `Clay_RenderCommand.textContent` will be populated with a `Clay_String` _slice_ of the original string passed in (i.e. wrapping doesn't reallocate, it just returns a `Clay_String` pointing to the start of the new line with a `length`) +--- + ### CLAY_IMAGE **Usage** @@ -1059,11 +1199,11 @@ CLAY(CLAY_IMAGE({ .image = { .format = IMAGE_FORMAT_RGBA, .internalData = &image // Load an image somewhere in your code Image profilePicture = LoadImage("profilePicture.png"); // Declare a reusable image config -Clay_ImageElementConfig imageConfig = (Clay_ImageElementConfig) { .imageData = &profilePicture, .height = 60, .width = 60 }; +Clay_ImageElementConfig imageConfig = (Clay_ImageElementConfig) { .imageData = &profilePicture, .sourceDimensions = {60, 60} }; // Declare an image element using a reusable config CLAY(CLAY_IMAGE(imageConfig)) {} // Declare an image element using an inline config -CLAY(CLAY_IMAGE({ .imageData = &profilePicture, .height = 60, .width = 60 })) {} +CLAY(CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {} // Rendering example Image *imageToRender = renderCommand->elementConfig.imageElementConfig->imageData; ``` @@ -1072,6 +1212,8 @@ Image *imageToRender = renderCommand->elementConfig.imageElementConfig->imageDat Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand`s with `commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE` will be created. The user will need to access `renderCommand->elementConfig.imageElementConfig->imageData` to retrieve image data referenced during layout creation. It's also up to the user to decide how / if they wish to blend `rectangleElementConfig->color` with the image. +--- + ### CLAY_SCROLL **Usage** @@ -1131,6 +1273,8 @@ CLAY(CLAY_SCROLL(.vertical = true)) { } ``` +--- + ### CLAY_BORDER **Usage** @@ -1248,6 +1392,8 @@ CLAY( Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand` with `commandType = CLAY_RENDER_COMMAND_TYPE_BORDER` representing the container will be created. Rendering of borders and rounded corners is left up to the user. See the provided [Raylib Renderer](https://github.com/nicbarker/clay/tree/main/renderers/raylib) for examples of how to draw borders using line and curve primitives. +--- + ### CLAY_FLOATING **Usage** @@ -1459,6 +1605,8 @@ When using `.parentId`, the floating container can be declared anywhere after `B `CLAY_FLOATING` elements will not generate any render commands. +--- + ### CLAY_CUSTOM_ELEMENT **Usage** @@ -1585,6 +1733,8 @@ The number of characters in the string, _not including an optional null terminat A pointer to the contents of the string. This data is not guaranteed to be null terminated, so if you are passing it to code that expects standard null terminated C strings, you will need to copy the data and append a null terminator. +--- + ### Clay_ElementId ```C @@ -1622,6 +1772,7 @@ If this id was generated using [CLAY_IDI](#clay_idi), `.baseId` is the hash of t Stores the original string that was passed in when [CLAY_ID](#clay_id) or [CLAY_IDI](#clay_idi) were called. +--- ### Clay_RenderCommandArray @@ -1655,6 +1806,8 @@ Represents the total number of `Clay_RenderCommand` elements stored consecutivel An array of [Clay_RenderCommand](#clay_rendercommand)s representing the calculated layout. If there was at least one render command, this array will contain elements from `.internalArray[0]` to `.internalArray[.length - 1]`. +--- + ### Clay_RenderCommand ```C @@ -1721,6 +1874,8 @@ Only used if `.commandType == CLAY_RENDER_COMMAND_TYPE_TEXT`. A `Clay_String` co The id that was originally used with the element macro that created this render command. See [CLAY_ID](#clay_id) for details. +--- + ### Clay_ScrollContainerData ```C @@ -1770,6 +1925,8 @@ Dimensions representing the inner width and height of the content _inside_ the s The [Clay_ScrollElementConfig](#clay_scroll) for the matching scroll container element. +--- + ### Clay_PointerData ```C @@ -1883,4 +2040,4 @@ A [Clay_String](#clay_string) that provides a human readable description of the A generic pointer to extra userdata that is transparently passed through from `Clay_Initialize` to Clay's error handler callback. Defaults to NULL. ---- \ No newline at end of file +--- diff --git a/bindings/odin/clay-odin/linux/clay.a b/bindings/odin/clay-odin/linux/clay.a index 6dfd1c8..e439b7b 100644 Binary files a/bindings/odin/clay-odin/linux/clay.a and b/bindings/odin/clay-odin/linux/clay.a differ diff --git a/bindings/odin/clay-odin/macos-arm64/clay.a b/bindings/odin/clay-odin/macos-arm64/clay.a index e7a1779..9abdeb4 100644 Binary files a/bindings/odin/clay-odin/macos-arm64/clay.a and b/bindings/odin/clay-odin/macos-arm64/clay.a differ diff --git a/bindings/odin/clay-odin/macos/clay.a b/bindings/odin/clay-odin/macos/clay.a index 2642a7d..59abf45 100644 Binary files a/bindings/odin/clay-odin/macos/clay.a and b/bindings/odin/clay-odin/macos/clay.a differ diff --git a/bindings/odin/clay-odin/wasm/clay.o b/bindings/odin/clay-odin/wasm/clay.o index 6b65e1a..5d29135 100644 Binary files a/bindings/odin/clay-odin/wasm/clay.o and b/bindings/odin/clay-odin/wasm/clay.o differ diff --git a/bindings/odin/clay-odin/windows/clay.lib b/bindings/odin/clay-odin/windows/clay.lib index 072a1dc..711a701 100644 Binary files a/bindings/odin/clay-odin/windows/clay.lib and b/bindings/odin/clay-odin/windows/clay.lib differ diff --git a/clay.h b/clay.h index 18a4396..061f4bf 100644 --- a/clay.h +++ b/clay.h @@ -21,6 +21,14 @@ #ifndef CLAY_HEADER #define CLAY_HEADER +#if !( \ + (defined(__cplusplus) && __cplusplus >= 202002L) || \ + (defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ + defined(_MSC_VER) \ +) +#error "Clay requires C99, C++20, or MSVC" +#endif + #ifdef CLAY_WASM #define CLAY_WASM_EXPORT(name) __attribute__((export_name(name))) #else @@ -62,15 +70,9 @@ #define CLAY_CORNER_RADIUS(radius) (CLAY__INIT(Clay_CornerRadius) { radius, radius, radius, radius }) -#define CLAY__STRUCT_1_ARGS(a) a -#define CLAY__STRUCT_0_ARGS() CLAY__DEFAULT_STRUCT -#define CLAY__STRUCT_OVERRIDE(_0, _1, NAME, ...) NAME +#define CLAY_SIZING_FIT(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { __VA_ARGS__ } }, .type = CLAY__SIZING_TYPE_FIT }) -#define CLAY__SIZING_FIT_INTERNAL(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = __VA_ARGS__ }, .type = CLAY__SIZING_TYPE_FIT }) -#define CLAY_SIZING_FIT(...) CLAY__SIZING_FIT_INTERNAL(CLAY__STRUCT_OVERRIDE("empty", ##__VA_ARGS__, CLAY__STRUCT_1_ARGS, CLAY__STRUCT_0_ARGS)(__VA_ARGS__)) - -#define CLAY__SIZING_GROW_INTERNAL(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = __VA_ARGS__ }, .type = CLAY__SIZING_TYPE_GROW }) -#define CLAY_SIZING_GROW(...) CLAY__SIZING_GROW_INTERNAL(CLAY__STRUCT_OVERRIDE("empty", ##__VA_ARGS__, CLAY__STRUCT_1_ARGS, CLAY__STRUCT_0_ARGS)(__VA_ARGS__)) +#define CLAY_SIZING_GROW(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { __VA_ARGS__ } }, .type = CLAY__SIZING_TYPE_GROW }) #define CLAY_SIZING_FIXED(fixedSize) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { fixedSize, fixedSize } }, .type = CLAY__SIZING_TYPE_FIXED }) @@ -86,7 +88,12 @@ #define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0])) -#define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .length = CLAY__STRING_LENGTH(string), .chars = (string) }) +#define CLAY__ENSURE_STRING_LITERAL(x) ("" x "") + +// Note: If an error led you here, it's because CLAY_STRING can only be used with string literals, i.e. CLAY_STRING("SomeString") and not CLAY_STRING(yourString) +#define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }) + +#define CLAY_STRING_CONST(string) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) } static uint8_t CLAY__ELEMENT_DEFINITION_LATCH; @@ -117,7 +124,7 @@ static uint8_t CLAY__ELEMENT_DEFINITION_LATCH; */ #define CLAY(...) \ for (\ - CLAY__ELEMENT_DEFINITION_LATCH = (Clay__OpenElement(), ##__VA_ARGS__, Clay__ElementPostConfiguration(), 0); \ + CLAY__ELEMENT_DEFINITION_LATCH = (Clay__OpenElement(), __VA_ARGS__, Clay__ElementPostConfiguration(), 0); \ CLAY__ELEMENT_DEFINITION_LATCH < 1; \ ++CLAY__ELEMENT_DEFINITION_LATCH, Clay__CloseElement() \ ) @@ -182,6 +189,8 @@ CLAY__TYPEDEF(Clay__StringArray, struct { Clay_String *internalArray; }); +typedef struct Clay_Context Clay_Context; + CLAY__TYPEDEF(Clay_Arena, struct { uintptr_t nextAllocation; size_t capacity; @@ -489,7 +498,9 @@ CLAY__TYPEDEF(Clay_ErrorHandler, struct { uint32_t Clay_MinMemorySize(void); Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset); void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown); -void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler); +Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler); +Clay_Context* Clay_GetCurrentContext(void); +void Clay_SetCurrentContext(Clay_Context* context); void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime); void Clay_SetLayoutDimensions(Clay_Dimensions dimensions); void Clay_BeginLayout(void); @@ -506,7 +517,9 @@ Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, void Clay_SetDebugModeEnabled(bool enabled); bool Clay_IsDebugModeEnabled(void); void Clay_SetCullingEnabled(bool enabled); +int32_t Clay_GetMaxElementCount(void); void Clay_SetMaxElementCount(int32_t maxElementCount); +int32_t Clay_GetMaxMeasureTextCacheWordCount(void); void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount); // Internal API functions required by macros @@ -551,13 +564,13 @@ extern uint32_t Clay__debugViewWidth; #define CLAY__MAXFLOAT 3.40282346638528859812e+38F #endif -bool Clay__warningsEnabled = true; -int32_t Clay__maxElementCount = 8192; -int32_t Clay__maxMeasureTextCacheWordCount = 16384; +Clay_Context *Clay__currentContext; +int32_t Clay__defaultMaxElementCount = 8192; +int32_t Clay__defaultMaxMeasureTextWordCacheCount = 16384; + void Clay__ErrorHandlerFunctionDefault(Clay_ErrorData errorText) { (void) errorText; } -Clay_ErrorHandler Clay__errorHandler = { .errorHandlerFunction = Clay__ErrorHandlerFunctionDefault }; Clay_String CLAY__SPACECHAR = { .length = 1, .chars = " " }; Clay_String CLAY__STRING_DEFAULT = { .length = 0, .chars = NULL }; @@ -568,8 +581,6 @@ CLAY__TYPEDEF(Clay_BooleanWarnings, struct { bool maxTextMeasureCacheExceeded; }); -Clay_BooleanWarnings Clay__booleanWarnings; - CLAY__TYPEDEF(Clay__Warning, struct { Clay_String baseMessage; Clay_String dynamicMessage; @@ -577,87 +588,17 @@ CLAY__TYPEDEF(Clay__Warning, struct { Clay__Warning CLAY__WARNING_DEFAULT = CLAY__DEFAULT_STRUCT; -#pragma region generated CLAY__TYPEDEF(Clay__WarningArray, struct { int32_t capacity; int32_t length; Clay__Warning *internalArray; }); -Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Arena *arena) { - size_t totalSizeBytes = capacity * sizeof(Clay_String); - Clay__WarningArray array = {.capacity = capacity, .length = 0}; - uintptr_t nextAllocAddress = arena->nextAllocation + (uintptr_t)arena->memory; - uintptr_t arenaOffsetAligned = nextAllocAddress + (CLAY__ALIGNMENT(Clay_String) - (nextAllocAddress % CLAY__ALIGNMENT(Clay_String))); - arenaOffsetAligned -= (uintptr_t)arena->memory; - if (arenaOffsetAligned + totalSizeBytes <= arena->capacity) { - array.internalArray = (Clay__Warning*)((uintptr_t)arena->memory + (uintptr_t)arenaOffsetAligned); - arena->nextAllocation = arenaOffsetAligned + totalSizeBytes; - } - else { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { - .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED, - .errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"), - .userData = Clay__errorHandler.userData }); - } - return array; -} - -Clay__WarningArray Clay_warnings = CLAY__DEFAULT_STRUCT; - -Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item) -{ - if (array->length < array->capacity) { - array->internalArray[array->length++] = item; - return &array->internalArray[array->length - 1]; - } - return &CLAY__WARNING_DEFAULT; -} - -void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, uint32_t alignment, Clay_Arena *arena) -{ - size_t totalSizeBytes = capacity * itemSize; - uintptr_t nextAllocAddress = arena->nextAllocation + (uintptr_t)arena->memory; - uintptr_t arenaOffsetAligned = nextAllocAddress + (alignment - (nextAllocAddress % alignment)); - arenaOffsetAligned -= (uintptr_t)arena->memory; - if (arenaOffsetAligned + totalSizeBytes <= arena->capacity) { - arena->nextAllocation = arenaOffsetAligned + totalSizeBytes; - return (void*)((uintptr_t)arena->memory + (uintptr_t)arenaOffsetAligned); - } - else { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { - .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED, - .errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"), - .userData = Clay__errorHandler.userData }); - } - return CLAY__NULL; -} - -bool Clay__Array_RangeCheck(int32_t index, int32_t length) -{ - if (index < length && index >= 0) { - return true; - } - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { - .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR, - .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."), - .userData = Clay__errorHandler.userData }); - return false; -} - -bool Clay__Array_AddCapacityCheck(int32_t length, int32_t capacity) -{ - if (length < capacity) { - return true; - } - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { - .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR, - .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."), - .userData = Clay__errorHandler.userData }); - return false; -} - -bool CLAY__BOOL_DEFAULT = false; +Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Arena *arena); +Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item); +void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, uint32_t alignment, Clay_Arena *arena); +bool Clay__Array_RangeCheck(int32_t index, int32_t length); +bool Clay__Array_AddCapacityCheck(int32_t length, int32_t capacity); // __GENERATED__ template array_define,array_allocate TYPE=bool NAME=Clay__BoolArray #pragma region generated @@ -1423,6 +1364,88 @@ Clay__CharArray Clay__CharArray_Allocate_Arena(int32_t capacity, Clay_Arena *are #pragma endregion // __GENERATED__ template +struct Clay_Context { + int32_t maxElementCount; + int32_t maxMeasureTextCacheWordCount; + bool warningsEnabled; + Clay_ErrorHandler errorHandler; + Clay_BooleanWarnings booleanWarnings; + Clay__WarningArray warnings; + + Clay_PointerData pointerInfo; + Clay_Dimensions layoutDimensions; + Clay_ElementId dynamicElementIndexBaseHash; + uint32_t dynamicElementIndex; + bool debugModeEnabled; + bool disableCulling; + bool externalScrollHandlingEnabled; + uint32_t debugSelectedElementId; + uint32_t generation; + uint64_t arenaResetOffset; + Clay_Arena internalArena; + // Layout Elements / Render Commands + Clay_LayoutElementArray layoutElements; + Clay_RenderCommandArray renderCommands; + Clay__int32_tArray openLayoutElementStack; + Clay__int32_tArray layoutElementChildren; + Clay__int32_tArray layoutElementChildrenBuffer; + Clay__TextElementDataArray textElementData; + Clay__LayoutElementPointerArray imageElementPointers; + Clay__int32_tArray reusableElementIndexBuffer; + Clay__int32_tArray layoutElementClipElementIds; + // Configs + Clay__LayoutConfigArray layoutConfigs; + Clay__ElementConfigArray elementConfigBuffer; + Clay__ElementConfigArray elementConfigs; + Clay__RectangleElementConfigArray rectangleElementConfigs; + Clay__TextElementConfigArray textElementConfigs; + Clay__ImageElementConfigArray imageElementConfigs; + Clay__FloatingElementConfigArray floatingElementConfigs; + Clay__ScrollElementConfigArray scrollElementConfigs; + Clay__CustomElementConfigArray customElementConfigs; + Clay__BorderElementConfigArray borderElementConfigs; + // Misc Data Structures + Clay__StringArray layoutElementIdStrings; + Clay__WrappedTextLineArray wrappedTextLines; + Clay__LayoutElementTreeNodeArray layoutElementTreeNodeArray1; + Clay__LayoutElementTreeRootArray layoutElementTreeRoots; + Clay__LayoutElementHashMapItemArray layoutElementsHashMapInternal; + Clay__int32_tArray layoutElementsHashMap; + Clay__MeasureTextCacheItemArray measureTextHashMapInternal; + Clay__int32_tArray measureTextHashMapInternalFreeList; + Clay__int32_tArray measureTextHashMap; + Clay__MeasuredWordArray measuredWords; + Clay__int32_tArray measuredWordsFreeList; + Clay__int32_tArray openClipElementStack; + Clay__ElementIdArray pointerOverIds; + Clay__ScrollContainerDataInternalArray scrollContainerDatas; + Clay__BoolArray treeNodeVisited; + Clay__CharArray dynamicStringData; + Clay__DebugElementDataArray debugElementData; +}; + +struct Clay__AlignClay_Context { + char c; + Clay_Context x; +}; +typedef struct { + Clay_Context wrapped; +} Clay__Clay_ContextWrapper; + +Clay_Context* Clay__Context_Allocate_Arena(Clay_Arena *arena) { + uint32_t alignment = CLAY__ALIGNMENT(Clay_Context); + size_t totalSizeBytes = sizeof(Clay_Context); + uintptr_t nextAllocAddress = arena->nextAllocation + (uintptr_t)arena->memory; + uintptr_t arenaOffsetAligned = nextAllocAddress + (alignment - (nextAllocAddress & alignment)); + arenaOffsetAligned -= (uintptr_t)arena->memory; + if (arenaOffsetAligned + totalSizeBytes > arena->capacity) + { + return NULL; + } + arena->nextAllocation = arenaOffsetAligned + totalSizeBytes; + return (Clay_Context*)((uintptr_t)arena->memory + arenaOffsetAligned); +} + Clay_String Clay__WriteStringToCharBuffer(Clay__CharArray *buffer, Clay_String string) { for (int32_t i = 0; i < string.length; i++) { buffer->internalArray[buffer->length + i] = string.chars[i]; @@ -1431,60 +1454,6 @@ 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) }; } -// Global Variable Definitions ---------------------------------------------- -Clay_PointerData Clay__pointerInfo = { .position = {-1, -1} }; -Clay_Dimensions Clay__layoutDimensions = CLAY__DEFAULT_STRUCT; -Clay_ElementId Clay__dynamicElementIndexBaseHash = { .id = 128476991, .stringId = { .length = 8, .chars = "Auto ID" } }; -uint32_t Clay__dynamicElementIndex = 0; -bool Clay__debugModeEnabled = false; -bool Clay__disableCulling = false; -bool Clay__externalScrollHandlingEnabled = false; -uint32_t Clay__debugSelectedElementId = 0; -uint32_t Clay__debugViewWidth = 400; -Clay_Color Clay__debugViewHighlightColor = { 168, 66, 28, 100 }; -uint32_t Clay__generation = 0; -uint64_t Clay__arenaResetOffset = 0; -Clay_Arena Clay__internalArena; -// Layout Elements / Render Commands -Clay_LayoutElementArray Clay__layoutElements; -Clay_RenderCommandArray Clay__renderCommands; -Clay__int32_tArray Clay__openLayoutElementStack; -Clay__int32_tArray Clay__layoutElementChildren; -Clay__int32_tArray Clay__layoutElementChildrenBuffer; -Clay__TextElementDataArray Clay__textElementData; -Clay__LayoutElementPointerArray Clay__imageElementPointers; -Clay__int32_tArray Clay__reusableElementIndexBuffer; -Clay__int32_tArray Clay__layoutElementClipElementIds; -// Configs -Clay__LayoutConfigArray Clay__layoutConfigs; -Clay__ElementConfigArray Clay__elementConfigBuffer; -Clay__ElementConfigArray Clay__elementConfigs; -Clay__RectangleElementConfigArray Clay__rectangleElementConfigs; -Clay__TextElementConfigArray Clay__textElementConfigs; -Clay__ImageElementConfigArray Clay__imageElementConfigs; -Clay__FloatingElementConfigArray Clay__floatingElementConfigs; -Clay__ScrollElementConfigArray Clay__scrollElementConfigs; -Clay__CustomElementConfigArray Clay__customElementConfigs; -Clay__BorderElementConfigArray Clay__borderElementConfigs; -// Misc Data Structures -Clay__StringArray Clay__layoutElementIdStrings; -Clay__WrappedTextLineArray Clay__wrappedTextLines; -Clay__LayoutElementTreeNodeArray Clay__layoutElementTreeNodeArray1; -Clay__LayoutElementTreeRootArray Clay__layoutElementTreeRoots; -Clay__LayoutElementHashMapItemArray Clay__layoutElementsHashMapInternal; -Clay__int32_tArray Clay__layoutElementsHashMap; -Clay__MeasureTextCacheItemArray Clay__measureTextHashMapInternal; -Clay__int32_tArray Clay__measureTextHashMapInternalFreeList; -Clay__int32_tArray Clay__measureTextHashMap; -Clay__MeasuredWordArray Clay__measuredWords; -Clay__int32_tArray Clay__measuredWordsFreeList; -Clay__int32_tArray Clay__openClipElementStack; -Clay__ElementIdArray Clay__pointerOverIds; -Clay__ScrollContainerDataInternalArray Clay__scrollContainerDatas; -Clay__BoolArray Clay__treeNodeVisited; -Clay__CharArray Clay__dynamicStringData; -Clay__DebugElementDataArray Clay__debugElementData; - #ifdef CLAY_WASM __attribute__((import_module("clay"), import_name("measureTextFunction"))) Clay_Dimensions Clay__MeasureText(Clay_String *text, Clay_TextElementConfig *config); __attribute__((import_module("clay"), import_name("queryScrollOffsetFunction"))) Clay_Vector2 Clay__QueryScrollOffset(uint32_t elementId); @@ -1494,11 +1463,13 @@ Clay__DebugElementDataArray Clay__debugElementData; #endif Clay_LayoutElement* Clay__GetOpenLayoutElement(void) { - return Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 1)); + Clay_Context* context = Clay_GetCurrentContext(); + return Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&context->openLayoutElementStack, context->openLayoutElementStack.length - 1)); } uint32_t Clay__GetParentElementId(void) { - return Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 2))->id; + Clay_Context* context = Clay_GetCurrentContext(); + return Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2))->id; } bool Clay__ElementHasConfig(Clay_LayoutElement *element, Clay__ElementConfigType type) { @@ -1612,55 +1583,57 @@ uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *con } Clay__MeasuredWord *Clay__AddMeasuredWord(Clay__MeasuredWord word, Clay__MeasuredWord *previousWord) { - if (Clay__measuredWordsFreeList.length > 0) { - uint32_t newItemIndex = Clay__int32_tArray_Get(&Clay__measuredWordsFreeList, (int)Clay__measuredWordsFreeList.length - 1); - Clay__measuredWordsFreeList.length--; - Clay__MeasuredWordArray_Set(&Clay__measuredWords, (int)newItemIndex, word); + Clay_Context* context = Clay_GetCurrentContext(); + if (context->measuredWordsFreeList.length > 0) { + uint32_t newItemIndex = Clay__int32_tArray_Get(&context->measuredWordsFreeList, (int)context->measuredWordsFreeList.length - 1); + context->measuredWordsFreeList.length--; + Clay__MeasuredWordArray_Set(&context->measuredWords, (int)newItemIndex, word); previousWord->next = (int32_t)newItemIndex; - return Clay__MeasuredWordArray_Get(&Clay__measuredWords, (int)newItemIndex); + return Clay__MeasuredWordArray_Get(&context->measuredWords, (int)newItemIndex); } else { - previousWord->next = (int32_t)Clay__measuredWords.length; - return Clay__MeasuredWordArray_Add(&Clay__measuredWords, word); + previousWord->next = (int32_t)context->measuredWords.length; + return Clay__MeasuredWordArray_Add(&context->measuredWords, word); } } Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_TextElementConfig *config) { + Clay_Context* context = Clay_GetCurrentContext(); #ifndef CLAY_WASM if (!Clay__MeasureText) { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED, .errorText = CLAY_STRING("Clay's internal MeasureText function is null. You may have forgotten to call Clay_SetMeasureTextFunction(), or passed a NULL function pointer by mistake."), - .userData = Clay__errorHandler.userData }); + .userData = context->errorHandler.userData }); return NULL; } #endif uint32_t id = Clay__HashTextWithConfig(text, config); - uint32_t hashBucket = id % (Clay__maxMeasureTextCacheWordCount / 32); + uint32_t hashBucket = id % (context->maxMeasureTextCacheWordCount / 32); int32_t elementIndexPrevious = 0; - int32_t elementIndex = Clay__measureTextHashMap.internalArray[hashBucket]; + int32_t elementIndex = context->measureTextHashMap.internalArray[hashBucket]; while (elementIndex != 0) { - Clay__MeasureTextCacheItem *hashEntry = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndex); + Clay__MeasureTextCacheItem *hashEntry = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndex); if (hashEntry->id == id) { - hashEntry->generation = Clay__generation; + hashEntry->generation = context->generation; return hashEntry; } // This element hasn't been seen in a few frames, delete the hash map item - if (Clay__generation - hashEntry->generation > 2) { + if (context->generation - hashEntry->generation > 2) { // Add all the measured words that were included in this measurement to the freelist int32_t nextWordIndex = hashEntry->measuredWordsStartIndex; while (nextWordIndex != -1) { - Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&Clay__measuredWords, nextWordIndex); - Clay__int32_tArray_Add(&Clay__measuredWordsFreeList, nextWordIndex); + Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&context->measuredWords, nextWordIndex); + Clay__int32_tArray_Add(&context->measuredWordsFreeList, nextWordIndex); nextWordIndex = measuredWord->next; } int32_t nextIndex = hashEntry->nextIndex; - Clay__MeasureTextCacheItemArray_Set(&Clay__measureTextHashMapInternal, elementIndex, CLAY__INIT(Clay__MeasureTextCacheItem) { .measuredWordsStartIndex = -1 }); - Clay__int32_tArray_Add(&Clay__measureTextHashMapInternalFreeList, elementIndex); + Clay__MeasureTextCacheItemArray_Set(&context->measureTextHashMapInternal, elementIndex, CLAY__INIT(Clay__MeasureTextCacheItem) { .measuredWordsStartIndex = -1 }); + Clay__int32_tArray_Add(&context->measureTextHashMapInternalFreeList, elementIndex); if (elementIndexPrevious == 0) { - Clay__measureTextHashMap.internalArray[hashBucket] = nextIndex; + context->measureTextHashMap.internalArray[hashBucket] = nextIndex; } else { - Clay__MeasureTextCacheItem *previousHashEntry = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndexPrevious); + Clay__MeasureTextCacheItem *previousHashEntry = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndexPrevious); previousHashEntry->nextIndex = nextIndex; } elementIndex = nextIndex; @@ -1671,26 +1644,26 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text } int32_t newItemIndex = 0; - Clay__MeasureTextCacheItem newCacheItem = { .measuredWordsStartIndex = -1, .id = id, .generation = Clay__generation }; + Clay__MeasureTextCacheItem newCacheItem = { .measuredWordsStartIndex = -1, .id = id, .generation = context->generation }; Clay__MeasureTextCacheItem *measured = NULL; - if (Clay__measureTextHashMapInternalFreeList.length > 0) { - newItemIndex = Clay__int32_tArray_Get(&Clay__measureTextHashMapInternalFreeList, Clay__measureTextHashMapInternalFreeList.length - 1); - Clay__measureTextHashMapInternalFreeList.length--; - Clay__MeasureTextCacheItemArray_Set(&Clay__measureTextHashMapInternal, newItemIndex, newCacheItem); - measured = Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, newItemIndex); + if (context->measureTextHashMapInternalFreeList.length > 0) { + newItemIndex = Clay__int32_tArray_Get(&context->measureTextHashMapInternalFreeList, context->measureTextHashMapInternalFreeList.length - 1); + context->measureTextHashMapInternalFreeList.length--; + Clay__MeasureTextCacheItemArray_Set(&context->measureTextHashMapInternal, newItemIndex, newCacheItem); + measured = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, newItemIndex); } else { - if (Clay__measureTextHashMapInternal.length == Clay__measureTextHashMapInternal.capacity - 1) { - if (Clay__booleanWarnings.maxTextMeasureCacheExceeded) { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + if (context->measureTextHashMapInternal.length == context->measureTextHashMapInternal.capacity - 1) { + if (context->booleanWarnings.maxTextMeasureCacheExceeded) { + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED, .errorText = CLAY_STRING("Clay ran out of capacity while attempting to measure text elements. Try using Clay_SetMaxElementCount() with a higher value."), - .userData = Clay__errorHandler.userData }); - Clay__booleanWarnings.maxTextMeasureCacheExceeded = true; + .userData = context->errorHandler.userData }); + context->booleanWarnings.maxTextMeasureCacheExceeded = true; } return &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT; } - measured = Clay__MeasureTextCacheItemArray_Add(&Clay__measureTextHashMapInternal, newCacheItem); - newItemIndex = Clay__measureTextHashMapInternal.length - 1; + measured = Clay__MeasureTextCacheItemArray_Add(&context->measureTextHashMapInternal, newCacheItem); + newItemIndex = context->measureTextHashMapInternal.length - 1; } int32_t start = 0; @@ -1701,13 +1674,13 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text Clay__MeasuredWord tempWord = { .next = -1 }; Clay__MeasuredWord *previousWord = &tempWord; while (end < text->length) { - if (Clay__measuredWords.length == Clay__measuredWords.capacity - 1) { - if (!Clay__booleanWarnings.maxTextMeasureCacheExceeded) { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + if (context->measuredWords.length == context->measuredWords.capacity - 1) { + if (!context->booleanWarnings.maxTextMeasureCacheExceeded) { + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED, .errorText = CLAY_STRING("Clay has run out of space in it's internal text measurement cache. Try using Clay_SetMaxMeasureTextCacheWordCount() (default 16384, with 1 unit storing 1 measured word)."), - .userData = Clay__errorHandler.userData }); - Clay__booleanWarnings.maxTextMeasureCacheExceeded = true; + .userData = context->errorHandler.userData }); + context->booleanWarnings.maxTextMeasureCacheExceeded = true; } return &CLAY__MEASURE_TEXT_CACHE_ITEM_DEFAULT; } @@ -1744,9 +1717,9 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text measured->unwrappedDimensions.height = measuredHeight; if (elementIndexPrevious != 0) { - Clay__MeasureTextCacheItemArray_Get(&Clay__measureTextHashMapInternal, elementIndexPrevious)->nextIndex = newItemIndex; + Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndexPrevious)->nextIndex = newItemIndex; } else { - Clay__measureTextHashMap.internalArray[hashBucket] = newItemIndex; + context->measureTextHashMap.internalArray[hashBucket] = newItemIndex; } return measured; } @@ -1756,27 +1729,28 @@ bool Clay__PointIsInsideRect(Clay_Vector2 point, Clay_BoundingBox rect) { } Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Clay_LayoutElement* layoutElement) { - if (Clay__layoutElementsHashMapInternal.length == Clay__layoutElementsHashMapInternal.capacity - 1) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->layoutElementsHashMapInternal.length == context->layoutElementsHashMapInternal.capacity - 1) { return NULL; } - Clay_LayoutElementHashMapItem item = { .elementId = elementId, .layoutElement = layoutElement, .nextIndex = -1, .generation = Clay__generation + 1 }; - uint32_t hashBucket = elementId.id % Clay__layoutElementsHashMap.capacity; + Clay_LayoutElementHashMapItem item = { .elementId = elementId, .layoutElement = layoutElement, .nextIndex = -1, .generation = context->generation + 1 }; + uint32_t hashBucket = elementId.id % context->layoutElementsHashMap.capacity; int32_t hashItemPrevious = -1; - int32_t hashItemIndex = Clay__layoutElementsHashMap.internalArray[hashBucket]; + int32_t hashItemIndex = context->layoutElementsHashMap.internalArray[hashBucket]; while (hashItemIndex != -1) { // Just replace collision, not a big deal - leave it up to the end user - Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Get(&Clay__layoutElementsHashMapInternal, hashItemIndex); + Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemIndex); if (hashItem->elementId.id == elementId.id) { // Collision - resolve based on generation item.nextIndex = hashItem->nextIndex; - if (hashItem->generation <= Clay__generation) { // First collision - assume this is the "same" element - hashItem->generation = Clay__generation + 1; + if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element + hashItem->generation = context->generation + 1; hashItem->layoutElement = layoutElement; hashItem->debugData->collision = false; } else { // Multiple collisions this frame - two elements have the same ID - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_DUPLICATE_ID, .errorText = CLAY_STRING("An element with this ID was already previously declared during this layout."), - .userData = Clay__errorHandler.userData }); - if (Clay__debugModeEnabled) { + .userData = context->errorHandler.userData }); + if (context->debugModeEnabled) { hashItem->debugData->collision = true; } } @@ -1785,21 +1759,22 @@ Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Cl hashItemPrevious = hashItemIndex; hashItemIndex = hashItem->nextIndex; } - Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Add(&Clay__layoutElementsHashMapInternal, item); - hashItem->debugData = Clay__DebugElementDataArray_Add(&Clay__debugElementData, CLAY__INIT(Clay__DebugElementData) CLAY__DEFAULT_STRUCT); + Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Add(&context->layoutElementsHashMapInternal, item); + hashItem->debugData = Clay__DebugElementDataArray_Add(&context->debugElementData, CLAY__INIT(Clay__DebugElementData) CLAY__DEFAULT_STRUCT); if (hashItemPrevious != -1) { - Clay__LayoutElementHashMapItemArray_Get(&Clay__layoutElementsHashMapInternal, hashItemPrevious)->nextIndex = (int32_t)Clay__layoutElementsHashMapInternal.length - 1; + Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemPrevious)->nextIndex = (int32_t)context->layoutElementsHashMapInternal.length - 1; } else { - Clay__layoutElementsHashMap.internalArray[hashBucket] = (int32_t)Clay__layoutElementsHashMapInternal.length - 1; + context->layoutElementsHashMap.internalArray[hashBucket] = (int32_t)context->layoutElementsHashMapInternal.length - 1; } return hashItem; } Clay_LayoutElementHashMapItem *Clay__GetHashMapItem(uint32_t id) { - uint32_t hashBucket = id % Clay__layoutElementsHashMap.capacity; - int32_t elementIndex = Clay__layoutElementsHashMap.internalArray[hashBucket]; + Clay_Context* context = Clay_GetCurrentContext(); + uint32_t hashBucket = id % context->layoutElementsHashMap.capacity; + int32_t elementIndex = context->layoutElementsHashMap.internalArray[hashBucket]; while (elementIndex != -1) { - Clay_LayoutElementHashMapItem *hashEntry = Clay__LayoutElementHashMapItemArray_Get(&Clay__layoutElementsHashMapInternal, elementIndex); + Clay_LayoutElementHashMapItem *hashEntry = Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, elementIndex); if (hashEntry->elementId.id == id) { return hashEntry; } @@ -1809,15 +1784,17 @@ Clay_LayoutElementHashMapItem *Clay__GetHashMapItem(uint32_t id) { } 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_Context* context = Clay_GetCurrentContext(); + Clay_LayoutElement *parentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2)); Clay_ElementId elementId = Clay__HashNumber(parentElement->childrenOrTextContent.children.length, parentElement->id); openLayoutElement->id = elementId.id; Clay__AddHashMapItem(elementId, openLayoutElement); - Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId); + Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId); } void Clay__ElementPostConfiguration(void) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); @@ -1831,9 +1808,9 @@ void Clay__ElementPostConfiguration(void) { } // Loop through element configs and handle special cases - openLayoutElement->elementConfigs.internalArray = &Clay__elementConfigs.internalArray[Clay__elementConfigs.length]; + openLayoutElement->elementConfigs.internalArray = &context->elementConfigs.internalArray[context->elementConfigs.length]; for (int32_t elementConfigIndex = 0; elementConfigIndex < openLayoutElement->elementConfigs.length; elementConfigIndex++) { - Clay_ElementConfig *config = Clay__ElementConfigArray_Add(&Clay__elementConfigs, *Clay__ElementConfigArray_Get(&Clay__elementConfigBuffer, Clay__elementConfigBuffer.length - openLayoutElement->elementConfigs.length + elementConfigIndex)); + Clay_ElementConfig *config = Clay__ElementConfigArray_Add(&context->elementConfigs, *Clay__ElementConfigArray_Get(&context->elementConfigBuffer, context->elementConfigBuffer.length - openLayoutElement->elementConfigs.length + elementConfigIndex)); openLayoutElement->configsEnabled |= config->type; switch (config->type) { case CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE: @@ -1841,7 +1818,7 @@ void Clay__ElementPostConfiguration(void) { case CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER: { 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)); + Clay_LayoutElement *hierarchicalParent = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2)); if (!hierarchicalParent) { break; } @@ -1850,24 +1827,24 @@ void Clay__ElementPostConfiguration(void) { // If no parent id was specified, attach to the elements direct hierarchical parent Clay_FloatingElementConfig newConfig = *floatingConfig; newConfig.parentId = hierarchicalParent->id; - floatingConfig = Clay__FloatingElementConfigArray_Add(&Clay__floatingElementConfigs, newConfig); + floatingConfig = Clay__FloatingElementConfigArray_Add(&context->floatingElementConfigs, newConfig); config->config.floatingElementConfig = floatingConfig; - if (Clay__openClipElementStack.length > 0) { - clipElementId = Clay__int32_tArray_Get(&Clay__openClipElementStack, (int)Clay__openClipElementStack.length - 1); + if (context->openClipElementStack.length > 0) { + clipElementId = Clay__int32_tArray_Get(&context->openClipElementStack, (int)context->openClipElementStack.length - 1); } } else { Clay_LayoutElementHashMapItem *parentItem = Clay__GetHashMapItem(floatingConfig->parentId); if (!parentItem) { - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND, .errorText = CLAY_STRING("A floating element was declared with a parentId, but no element with that ID was found."), - .userData = Clay__errorHandler.userData }); + .userData = context->errorHandler.userData }); } else { - clipElementId = Clay__int32_tArray_Get(&Clay__layoutElementClipElementIds, parentItem->layoutElement - Clay__layoutElements.internalArray); + clipElementId = Clay__int32_tArray_Get(&context->layoutElementClipElementIds, parentItem->layoutElement - context->layoutElements.internalArray); } } - Clay__LayoutElementTreeRootArray_Add(&Clay__layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) { - .layoutElementIndex = Clay__int32_tArray_Get(&Clay__openLayoutElementStack, Clay__openLayoutElementStack.length - 1), + Clay__LayoutElementTreeRootArray_Add(&context->layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) { + .layoutElementIndex = Clay__int32_tArray_Get(&context->openLayoutElementStack, context->openLayoutElementStack.length - 1), .parentId = floatingConfig->parentId, .clipElementId = clipElementId, .zIndex = floatingConfig->zIndex, @@ -1875,11 +1852,11 @@ void Clay__ElementPostConfiguration(void) { break; } case CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER: { - Clay__int32_tArray_Add(&Clay__openClipElementStack, (int)openLayoutElement->id); + Clay__int32_tArray_Add(&context->openClipElementStack, (int)openLayoutElement->id); // Retrieve or create cached data to track scroll position across frames Clay__ScrollContainerDataInternal *scrollOffset = CLAY__NULL; - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (openLayoutElement->id == mapping->elementId) { scrollOffset = mapping; scrollOffset->layoutElement = openLayoutElement; @@ -1887,27 +1864,28 @@ void Clay__ElementPostConfiguration(void) { } } if (!scrollOffset) { - scrollOffset = Clay__ScrollContainerDataInternalArray_Add(&Clay__scrollContainerDatas, CLAY__INIT(Clay__ScrollContainerDataInternal){.layoutElement = openLayoutElement, .scrollOrigin = {-1,-1}, .elementId = openLayoutElement->id, .openThisFrame = true}); + scrollOffset = Clay__ScrollContainerDataInternalArray_Add(&context->scrollContainerDatas, CLAY__INIT(Clay__ScrollContainerDataInternal){.layoutElement = openLayoutElement, .scrollOrigin = {-1,-1}, .elementId = openLayoutElement->id, .openThisFrame = true}); } - if (Clay__externalScrollHandlingEnabled) { + if (context->externalScrollHandlingEnabled) { scrollOffset->scrollPosition = Clay__QueryScrollOffset(scrollOffset->elementId); } break; } case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: break; case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: { - Clay__LayoutElementPointerArray_Add(&Clay__imageElementPointers, openLayoutElement); + Clay__LayoutElementPointerArray_Add(&context->imageElementPointers, openLayoutElement); break; } case CLAY__ELEMENT_CONFIG_TYPE_TEXT: default: break; } } - Clay__elementConfigBuffer.length -= openLayoutElement->elementConfigs.length; + context->elementConfigBuffer.length -= openLayoutElement->elementConfigs.length; } void Clay__CloseElement(void) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); @@ -1918,16 +1896,16 @@ void Clay__CloseElement(void) { Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(openLayoutElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig; elementHasScrollHorizontal = scrollConfig->horizontal; elementHasScrollVertical = scrollConfig->vertical; - Clay__openClipElementStack.length--; + context->openClipElementStack.length--; } // Attach children to the current open element - openLayoutElement->childrenOrTextContent.children.elements = &Clay__layoutElementChildren.internalArray[Clay__layoutElementChildren.length]; + openLayoutElement->childrenOrTextContent.children.elements = &context->layoutElementChildren.internalArray[context->layoutElementChildren.length]; if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { openLayoutElement->dimensions.width = (float)layoutConfig->padding.x * 2; for (int32_t i = 0; i < openLayoutElement->childrenOrTextContent.children.length; i++) { - int32_t childIndex = Clay__int32_tArray_Get(&Clay__layoutElementChildrenBuffer, (int)Clay__layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i); - Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&Clay__layoutElements, childIndex); + int32_t childIndex = Clay__int32_tArray_Get(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i); + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex); openLayoutElement->dimensions.width += child->dimensions.width; openLayoutElement->dimensions.height = CLAY__MAX(openLayoutElement->dimensions.height, child->dimensions.height + layoutConfig->padding.y * 2); // Minimum size of child elements doesn't matter to scroll containers as they can shrink and hide their contents @@ -1937,7 +1915,7 @@ void Clay__CloseElement(void) { if (!elementHasScrollVertical) { openLayoutElement->minDimensions.height = CLAY__MAX(openLayoutElement->minDimensions.height, child->minDimensions.height + layoutConfig->padding.y * 2); } - Clay__int32_tArray_Add(&Clay__layoutElementChildren, childIndex); + Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex); } float childGap = (float)(CLAY__MAX(openLayoutElement->childrenOrTextContent.children.length - 1, 0) * layoutConfig->childGap); openLayoutElement->dimensions.width += childGap; // TODO this is technically a bug with childgap and scroll containers @@ -1946,8 +1924,8 @@ void Clay__CloseElement(void) { else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) { openLayoutElement->dimensions.height = (float)layoutConfig->padding.y * 2; for (int32_t i = 0; i < openLayoutElement->childrenOrTextContent.children.length; i++) { - int32_t childIndex = Clay__int32_tArray_Get(&Clay__layoutElementChildrenBuffer, (int)Clay__layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i); - Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&Clay__layoutElements, childIndex); + int32_t childIndex = Clay__int32_tArray_Get(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i); + Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex); openLayoutElement->dimensions.height += child->dimensions.height; openLayoutElement->dimensions.width = CLAY__MAX(openLayoutElement->dimensions.width, child->dimensions.width + layoutConfig->padding.x * 2); // Minimum size of child elements doesn't matter to scroll containers as they can shrink and hide their contents @@ -1957,14 +1935,14 @@ void Clay__CloseElement(void) { if (!elementHasScrollHorizontal) { openLayoutElement->minDimensions.width = CLAY__MAX(openLayoutElement->minDimensions.width, child->minDimensions.width + layoutConfig->padding.x * 2); } - Clay__int32_tArray_Add(&Clay__layoutElementChildren, childIndex); + Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex); } float childGap = (float)(CLAY__MAX(openLayoutElement->childrenOrTextContent.children.length - 1, 0) * layoutConfig->childGap); openLayoutElement->dimensions.height += childGap; // TODO this is technically a bug with childgap and scroll containers openLayoutElement->minDimensions.height += childGap; } - Clay__layoutElementChildrenBuffer.length -= openLayoutElement->childrenOrTextContent.children.length; + context->layoutElementChildrenBuffer.length -= openLayoutElement->childrenOrTextContent.children.length; // Clamp element min and max width to the values configured in the layout if (layoutConfig->sizing.width.type != CLAY__SIZING_TYPE_PERCENT) { @@ -1991,33 +1969,35 @@ void Clay__CloseElement(void) { bool elementIsFloating = Clay__ElementHasConfig(openLayoutElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER); // Close the currently open element - int32_t closingElementIndex = Clay__int32_tArray_RemoveSwapback(&Clay__openLayoutElementStack, (int)Clay__openLayoutElementStack.length - 1); + int32_t closingElementIndex = Clay__int32_tArray_RemoveSwapback(&context->openLayoutElementStack, (int)context->openLayoutElementStack.length - 1); openLayoutElement = Clay__GetOpenLayoutElement(); - if (!elementIsFloating && Clay__openLayoutElementStack.length > 1) { + if (!elementIsFloating && context->openLayoutElementStack.length > 1) { openLayoutElement->childrenOrTextContent.children.length++; - Clay__int32_tArray_Add(&Clay__layoutElementChildrenBuffer, closingElementIndex); + Clay__int32_tArray_Add(&context->layoutElementChildrenBuffer, closingElementIndex); } } void Clay__OpenElement(void) { - if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__booleanWarnings.maxElementsExceeded) { - Clay__booleanWarnings.maxElementsExceeded = true; + Clay_Context* context = Clay_GetCurrentContext(); + if (context->layoutElements.length == context->layoutElements.capacity - 1 || context->booleanWarnings.maxElementsExceeded) { + context->booleanWarnings.maxElementsExceeded = true; return; } Clay_LayoutElement layoutElement = CLAY__DEFAULT_STRUCT; - Clay_LayoutElementArray_Add(&Clay__layoutElements, layoutElement); - Clay__int32_tArray_Add(&Clay__openLayoutElementStack, Clay__layoutElements.length - 1); - if (Clay__openClipElementStack.length > 0) { - Clay__int32_tArray_Set(&Clay__layoutElementClipElementIds, Clay__layoutElements.length - 1, Clay__int32_tArray_Get(&Clay__openClipElementStack, (int)Clay__openClipElementStack.length - 1)); + Clay_LayoutElementArray_Add(&context->layoutElements, layoutElement); + Clay__int32_tArray_Add(&context->openLayoutElementStack, context->layoutElements.length - 1); + if (context->openClipElementStack.length > 0) { + Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, Clay__int32_tArray_Get(&context->openClipElementStack, (int)context->openClipElementStack.length - 1)); } else { - Clay__int32_tArray_Set(&Clay__layoutElementClipElementIds, Clay__layoutElements.length - 1, 0); + Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, 0); } } void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig) { - if (Clay__layoutElements.length == Clay__layoutElements.capacity - 1 || Clay__booleanWarnings.maxElementsExceeded) { - Clay__booleanWarnings.maxElementsExceeded = true; + Clay_Context* context = Clay_GetCurrentContext(); + if (context->layoutElements.length == context->layoutElements.capacity - 1 || context->booleanWarnings.maxElementsExceeded) { + context->booleanWarnings.maxElementsExceeded = true; return; } Clay_LayoutElement *parentElement = Clay__GetOpenLayoutElement(); @@ -2025,152 +2005,136 @@ void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig) Clay__OpenElement(); Clay_LayoutElement * openLayoutElement = Clay__GetOpenLayoutElement(); - Clay__int32_tArray_Add(&Clay__layoutElementChildrenBuffer, Clay__layoutElements.length - 1); + Clay__int32_tArray_Add(&context->layoutElementChildrenBuffer, context->layoutElements.length - 1); Clay__MeasureTextCacheItem *textMeasured = Clay__MeasureTextCached(&text, textConfig); Clay_ElementId elementId = Clay__HashString(CLAY_STRING("Text"), parentElement->childrenOrTextContent.children.length, parentElement->id); openLayoutElement->id = elementId.id; Clay__AddHashMapItem(elementId, openLayoutElement); - Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId); + Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId); Clay_Dimensions textDimensions = { .width = textMeasured->unwrappedDimensions.width, .height = textConfig->lineHeight > 0 ? (float)textConfig->lineHeight : textMeasured->unwrappedDimensions.height }; openLayoutElement->dimensions = textDimensions; openLayoutElement->minDimensions = CLAY__INIT(Clay_Dimensions) { .width = textMeasured->unwrappedDimensions.height, .height = textDimensions.height }; // TODO not sure this is the best way to decide min width for text - openLayoutElement->childrenOrTextContent.textElementData = Clay__TextElementDataArray_Add(&Clay__textElementData, CLAY__INIT(Clay__TextElementData) { .text = text, .preferredDimensions = textMeasured->unwrappedDimensions, .elementIndex = Clay__layoutElements.length - 1 }); + openLayoutElement->childrenOrTextContent.textElementData = Clay__TextElementDataArray_Add(&context->textElementData, CLAY__INIT(Clay__TextElementData) { .text = text, .preferredDimensions = textMeasured->unwrappedDimensions, .elementIndex = context->layoutElements.length - 1 }); openLayoutElement->elementConfigs = CLAY__INIT(Clay__ElementConfigArraySlice) { .length = 1, - .internalArray = Clay__ElementConfigArray_Add(&Clay__elementConfigs, CLAY__INIT(Clay_ElementConfig) { .type = CLAY__ELEMENT_CONFIG_TYPE_TEXT, .config = { .textElementConfig = textConfig }}) + .internalArray = Clay__ElementConfigArray_Add(&context->elementConfigs, CLAY__INIT(Clay_ElementConfig) { .type = CLAY__ELEMENT_CONFIG_TYPE_TEXT, .config = { .textElementConfig = textConfig }}) }; openLayoutElement->configsEnabled |= CLAY__ELEMENT_CONFIG_TYPE_TEXT; openLayoutElement->layoutConfig = &CLAY_LAYOUT_DEFAULT; // Close the currently open element - Clay__int32_tArray_RemoveSwapback(&Clay__openLayoutElementStack, (int)Clay__openLayoutElementStack.length - 1); + Clay__int32_tArray_RemoveSwapback(&context->openLayoutElementStack, (int)context->openLayoutElementStack.length - 1); } -void Clay__InitializeEphemeralMemory(Clay_Arena *arena) { +void Clay__InitializeEphemeralMemory(Clay_Context* context) { + int32_t maxElementCount = context->maxElementCount; // Ephemeral Memory - reset every frame - Clay__internalArena.nextAllocation = Clay__arenaResetOffset; + Clay_Arena *arena = &context->internalArena; + arena->nextAllocation = context->arenaResetOffset; - Clay__layoutElementChildrenBuffer = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElements = Clay_LayoutElementArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay_warnings = Clay__WarningArray_Allocate_Arena(100, arena); + context->layoutElementChildrenBuffer = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->layoutElements = Clay_LayoutElementArray_Allocate_Arena(maxElementCount, arena); + context->warnings = Clay__WarningArray_Allocate_Arena(100, arena); - Clay__layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__elementConfigBuffer = Clay__ElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__elementConfigs = Clay__ElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__rectangleElementConfigs = Clay__RectangleElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__scrollElementConfigs = Clay__ScrollElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__customElementConfigs = Clay__CustomElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__borderElementConfigs = Clay__BorderElementConfigArray_Allocate_Arena(Clay__maxElementCount, arena); + context->layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(maxElementCount, arena); + context->elementConfigBuffer = Clay__ElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->elementConfigs = Clay__ElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->rectangleElementConfigs = Clay__RectangleElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->scrollElementConfigs = Clay__ScrollElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->customElementConfigs = Clay__CustomElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->borderElementConfigs = Clay__BorderElementConfigArray_Allocate_Arena(maxElementCount, arena); - Clay__layoutElementIdStrings = Clay__StringArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__wrappedTextLines = Clay__WrappedTextLineArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElementTreeNodeArray1 = Clay__LayoutElementTreeNodeArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElementTreeRoots = Clay__LayoutElementTreeRootArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElementChildren = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__textElementData = Clay__TextElementDataArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__imageElementPointers = Clay__LayoutElementPointerArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__renderCommands = Clay_RenderCommandArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__treeNodeVisited = Clay__BoolArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__treeNodeVisited.length = Clay__treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list - Clay__openClipElementStack = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__reusableElementIndexBuffer = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElementClipElementIds = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__dynamicStringData = Clay__CharArray_Allocate_Arena(Clay__maxElementCount, arena); + context->layoutElementIdStrings = Clay__StringArray_Allocate_Arena(maxElementCount, arena); + context->wrappedTextLines = Clay__WrappedTextLineArray_Allocate_Arena(maxElementCount, arena); + context->layoutElementTreeNodeArray1 = Clay__LayoutElementTreeNodeArray_Allocate_Arena(maxElementCount, arena); + context->layoutElementTreeRoots = Clay__LayoutElementTreeRootArray_Allocate_Arena(maxElementCount, arena); + context->layoutElementChildren = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->textElementData = Clay__TextElementDataArray_Allocate_Arena(maxElementCount, arena); + context->imageElementPointers = Clay__LayoutElementPointerArray_Allocate_Arena(maxElementCount, arena); + context->renderCommands = Clay_RenderCommandArray_Allocate_Arena(maxElementCount, arena); + context->treeNodeVisited = Clay__BoolArray_Allocate_Arena(maxElementCount, arena); + context->treeNodeVisited.length = context->treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list + context->openClipElementStack = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->reusableElementIndexBuffer = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->layoutElementClipElementIds = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->dynamicStringData = Clay__CharArray_Allocate_Arena(maxElementCount, arena); } -void Clay__InitializePersistentMemory(Clay_Arena *arena) { +void Clay__InitializePersistentMemory(Clay_Context* context) { // Persistent memory - initialized once and not reset - Clay__scrollContainerDatas = Clay__ScrollContainerDataInternalArray_Allocate_Arena(10, arena); - Clay__layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(Clay__maxMeasureTextCacheWordCount, arena); - Clay__measureTextHashMap = Clay__int32_tArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__measuredWords = Clay__MeasuredWordArray_Allocate_Arena(Clay__maxMeasureTextCacheWordCount, arena); - Clay__pointerOverIds = Clay__ElementIdArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__debugElementData = Clay__DebugElementDataArray_Allocate_Arena(Clay__maxElementCount, arena); - Clay__arenaResetOffset = arena->nextAllocation; + int32_t maxElementCount = context->maxElementCount; + int32_t maxMeasureTextCacheWordCount = context->maxMeasureTextCacheWordCount; + Clay_Arena *arena = &context->internalArena; + + context->scrollContainerDatas = Clay__ScrollContainerDataInternalArray_Allocate_Arena(10, arena); + context->layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(maxElementCount, arena); + context->layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(maxElementCount, arena); + context->measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(maxMeasureTextCacheWordCount, arena); + context->measureTextHashMap = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena); + context->measuredWords = Clay__MeasuredWordArray_Allocate_Arena(maxMeasureTextCacheWordCount, arena); + context->pointerOverIds = Clay__ElementIdArray_Allocate_Arena(maxElementCount, arena); + context->debugElementData = Clay__DebugElementDataArray_Allocate_Arena(maxElementCount, arena); + context->arenaResetOffset = arena->nextAllocation; } -CLAY__TYPEDEF(Clay__SizeDistributionType, enum { - CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER, - CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER, - CLAY__SIZE_DISTRIBUTION_TYPE_GROW_CONTAINER, -}); +void Clay__CompressChildrenAlongAxis(bool xAxis, float totalSizeToDistribute, Clay__int32_tArray resizableContainerBuffer) { + Clay_Context* context = Clay_GetCurrentContext(); + Clay__int32_tArray largestContainers = context->openClipElementStack; + largestContainers.length = 0; -float Clay__DistributeSizeAmongChildren(bool xAxis, float sizeToDistribute, Clay__int32_tArray resizableContainerBuffer, Clay__SizeDistributionType distributionType) { - Clay__int32_tArray remainingElements = Clay__openClipElementStack; - remainingElements.length = 0; + while (totalSizeToDistribute > 0.1) { + 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_Get(&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_Get(&resizableContainerBuffer, i)); + } else if (childSize > largestSize) { + targetSize = largestSize; + largestSize = childSize; + largestContainers.length = 0; + Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); + } + else if (childSize > targetSize) { + targetSize = childSize; + } + } - for (int32_t i = 0; i < resizableContainerBuffer.length; ++i) { - Clay__int32_tArray_Add(&remainingElements, Clay__int32_tArray_Get(&resizableContainerBuffer, i)); - } - - while (sizeToDistribute != 0 && remainingElements.length > 0) { - float dividedSize = sizeToDistribute / (float)remainingElements.length; - for (int32_t childOffset = 0; childOffset < remainingElements.length; childOffset++) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&remainingElements, childOffset)); - Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; + targetSize = CLAY__MAX(targetSize, (largestSize * largestContainers.length) - totalSizeToDistribute) / largestContainers.length; + for (int32_t childOffset = 0; childOffset < largestContainers.length; childOffset++) { + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&largestContainers, childOffset)); float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; float childMinSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height; - bool canDistribute = true; - - if ((sizeToDistribute < 0 && *childSize == childSizing.size.minMax.min) || (sizeToDistribute > 0 && *childSize == childSizing.size.minMax.max)) { - canDistribute = false; - } - // Currently, we don't support squishing aspect ratio images on their Y axis as it would break ratio - else if (!xAxis && Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) { - canDistribute = false; - } - else { - switch (distributionType) { - case CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER: break; - case CLAY__SIZE_DISTRIBUTION_TYPE_GROW_CONTAINER: if (childSizing.type != CLAY__SIZING_TYPE_GROW) canDistribute = false; break; - case CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER: { - if (Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER)) { - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(childElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig; - if ((xAxis && !scrollConfig->horizontal) || (!xAxis && !scrollConfig->vertical)) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); - childOffset--; - continue; - } - } - } - } - } - - if (!canDistribute) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); - childOffset--; - continue; - } - float oldChildSize = *childSize; - *childSize = CLAY__MAX(CLAY__MAX(CLAY__MIN(childSizing.size.minMax.max, *childSize + dividedSize), childSizing.size.minMax.min), childMinSize); - float diff = *childSize - oldChildSize; - if (diff > -0.01 && diff < 0.01) { - Clay__int32_tArray_RemoveSwapback(&remainingElements, childOffset); + *childSize = CLAY__MAX(childMinSize, targetSize); + totalSizeToDistribute -= (oldChildSize - *childSize); + if (*childSize == childMinSize) { + Clay__int32_tArray_RemoveSwapback(&largestContainers, childOffset); childOffset--; - continue; } - sizeToDistribute -= diff; + } + + if (largestContainers.length == 0) { + break; } } - return (sizeToDistribute > -0.01 && sizeToDistribute < 0.01) ? 0 : sizeToDistribute; } void Clay__SizeContainersAlongAxis(bool xAxis) { - Clay__int32_tArray bfsBuffer = Clay__layoutElementChildrenBuffer; - Clay__int32_tArray resizableContainerBuffer = Clay__openLayoutElementStack; - for (int32_t rootIndex = 0; rootIndex < Clay__layoutElementTreeRoots.length; ++rootIndex) { + Clay_Context* context = Clay_GetCurrentContext(); + Clay__int32_tArray bfsBuffer = context->layoutElementChildrenBuffer; + Clay__int32_tArray resizableContainerBuffer = context->openLayoutElementStack; + for (int32_t rootIndex = 0; rootIndex < context->layoutElementTreeRoots.length; ++rootIndex) { bfsBuffer.length = 0; - Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, rootIndex); - Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)root->layoutElementIndex); + Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex); + Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex); Clay__int32_tArray_Add(&bfsBuffer, (int32_t)root->layoutElementIndex); // Size floating containers to their parents @@ -2193,7 +2157,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { for (int32_t i = 0; i < bfsBuffer.length; ++i) { int32_t parentIndex = Clay__int32_tArray_Get(&bfsBuffer, i); - Clay_LayoutElement *parent = Clay_LayoutElementArray_Get(&Clay__layoutElements, parentIndex); + Clay_LayoutElement *parent = Clay_LayoutElementArray_Get(&context->layoutElements, parentIndex); Clay_LayoutConfig *parentStyleConfig = parent->layoutConfig; int32_t growContainerCount = 0; float parentSize = xAxis ? parent->dimensions.width : parent->dimensions.height; @@ -2205,7 +2169,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { for (int32_t childOffset = 0; childOffset < parent->childrenOrTextContent.children.length; childOffset++) { int32_t childElementIndex = parent->childrenOrTextContent.children.elements[childOffset]; - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, childElementIndex); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex); Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height; @@ -2235,7 +2199,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { // Expand percentage containers to size for (int32_t childOffset = 0; childOffset < parent->childrenOrTextContent.children.length; childOffset++) { int32_t childElementIndex = parent->childrenOrTextContent.children.elements[childOffset]; - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, childElementIndex); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex); Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; if (childSizing.type == CLAY__SIZING_TYPE_PERCENT) { @@ -2254,7 +2218,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { if (sizingAlongAxis) { float sizeToDistribute = parentSize - parentPadding * 2 - innerContentSize; - // If the content is too large, compress the children as much as possible + // The content is too large, compress the children as much as possible if (sizeToDistribute < 0) { // If the parent can scroll in the axis direction in this direction, don't compress children, just leave them alone if (Clay__ElementHasConfig(parent, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER)) { @@ -2264,17 +2228,12 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { } } // Scrolling containers preferentially compress before others - sizeToDistribute = Clay__DistributeSizeAmongChildren(xAxis, sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_SCROLL_CONTAINER); - - // If there is still height to make up, remove it from all containers that haven't hit their minimum size - if (sizeToDistribute < 0) { - Clay__DistributeSizeAmongChildren(xAxis, sizeToDistribute, resizableContainerBuffer, CLAY__SIZE_DISTRIBUTION_TYPE_RESIZEABLE_CONTAINER); - } + Clay__CompressChildrenAlongAxis(xAxis, -sizeToDistribute, resizableContainerBuffer); // 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(&Clay__layoutElements, Clay__int32_tArray_Get(&resizableContainerBuffer, childOffset)); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&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; @@ -2294,7 +2253,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { // Sizing along the non layout axis ("off axis") } else { for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&resizableContainerBuffer, childOffset)); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&resizableContainerBuffer, childOffset)); Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height; float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; @@ -2325,7 +2284,8 @@ Clay_String Clay__IntToString(int32_t integer) { if (integer == 0) { return CLAY__INIT(Clay_String) { .length = 1, .chars = "0" }; } - char *chars = (char *)(Clay__dynamicStringData.internalArray + Clay__dynamicStringData.length); + Clay_Context* context = Clay_GetCurrentContext(); + char *chars = (char *)(context->dynamicStringData.internalArray + context->dynamicStringData.length); int32_t length = 0; int32_t sign = integer; @@ -2347,44 +2307,47 @@ Clay_String Clay__IntToString(int32_t integer) { chars[j] = chars[k]; chars[k] = temp; } - Clay__dynamicStringData.length += length; + context->dynamicStringData.length += length; return CLAY__INIT(Clay_String) { .length = length, .chars = chars }; } void Clay__AddRenderCommand(Clay_RenderCommand renderCommand) { - if (Clay__renderCommands.length < Clay__renderCommands.capacity - 1) { - Clay_RenderCommandArray_Add(&Clay__renderCommands, renderCommand); + Clay_Context* context = Clay_GetCurrentContext(); + if (context->renderCommands.length < context->renderCommands.capacity - 1) { + Clay_RenderCommandArray_Add(&context->renderCommands, renderCommand); } else { - if (!Clay__booleanWarnings.maxRenderCommandsExceeded) { - Clay__booleanWarnings.maxRenderCommandsExceeded = true; - Clay__errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + if (!context->booleanWarnings.maxRenderCommandsExceeded) { + context->booleanWarnings.maxRenderCommandsExceeded = true; + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { .errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED, .errorText = CLAY_STRING("Clay ran out of capacity while attempting to create render commands. This is usually caused by a large amount of wrapping text elements while close to the max element capacity. Try using Clay_SetMaxElementCount() with a higher value."), - .userData = Clay__errorHandler.userData }); + .userData = context->errorHandler.userData }); } } } bool Clay__ElementIsOffscreen(Clay_BoundingBox *boundingBox) { - if (Clay__disableCulling) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->disableCulling) { return false; } - return (boundingBox->x > (float)Clay__layoutDimensions.width) || - (boundingBox->y > (float)Clay__layoutDimensions.height) || + return (boundingBox->x > (float)context->layoutDimensions.width) || + (boundingBox->y > (float)context->layoutDimensions.height) || (boundingBox->x + boundingBox->width < 0) || (boundingBox->y + boundingBox->height < 0); } -void Clay__CalculateFinalLayout(void) { +void Clay__CalculateFinalLayout() { + Clay_Context* context = Clay_GetCurrentContext(); // Calculate sizing along the X axis Clay__SizeContainersAlongAxis(true); // Wrap text - for (int32_t textElementIndex = 0; textElementIndex < Clay__textElementData.length; ++textElementIndex) { - Clay__TextElementData *textElementData = Clay__TextElementDataArray_Get(&Clay__textElementData, textElementIndex); - textElementData->wrappedLines = CLAY__INIT(Clay__WrappedTextLineArraySlice) { .length = 0, .internalArray = &Clay__wrappedTextLines.internalArray[Clay__wrappedTextLines.length] }; - Clay_LayoutElement *containerElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)textElementData->elementIndex); + for (int32_t textElementIndex = 0; textElementIndex < context->textElementData.length; ++textElementIndex) { + Clay__TextElementData *textElementData = Clay__TextElementDataArray_Get(&context->textElementData, textElementIndex); + textElementData->wrappedLines = CLAY__INIT(Clay__WrappedTextLineArraySlice) { .length = 0, .internalArray = &context->wrappedTextLines.internalArray[context->wrappedTextLines.length] }; + Clay_LayoutElement *containerElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)textElementData->elementIndex); Clay_TextElementConfig *textConfig = Clay__FindElementConfigWithType(containerElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT).textElementConfig; Clay__MeasureTextCacheItem *measureTextCacheItem = Clay__MeasureTextCached(&textElementData->text, textConfig); float lineWidth = 0; @@ -2392,19 +2355,19 @@ void Clay__CalculateFinalLayout(void) { int32_t lineLengthChars = 0; int32_t lineStartOffset = 0; if (textElementData->preferredDimensions.width <= containerElement->dimensions.width) { - Clay__WrappedTextLineArray_Add(&Clay__wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { containerElement->dimensions, textElementData->text }); + Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { containerElement->dimensions, textElementData->text }); textElementData->wrappedLines.length++; continue; } int32_t wordIndex = measureTextCacheItem->measuredWordsStartIndex; while (wordIndex != -1) { - if (Clay__wrappedTextLines.length > Clay__wrappedTextLines.capacity - 1) { + if (context->wrappedTextLines.length > context->wrappedTextLines.capacity - 1) { break; } - Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&Clay__measuredWords, wordIndex); + Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&context->measuredWords, wordIndex); // Only word on the line is too large, just render it anyway if (lineLengthChars == 0 && lineWidth + measuredWord->width > containerElement->dimensions.width) { - Clay__WrappedTextLineArray_Add(&Clay__wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { measuredWord->width, lineHeight }, { .length = measuredWord->length, .chars = &textElementData->text.chars[measuredWord->startOffset] } }); + Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { measuredWord->width, lineHeight }, { .length = measuredWord->length, .chars = &textElementData->text.chars[measuredWord->startOffset] } }); textElementData->wrappedLines.length++; wordIndex = measuredWord->next; lineStartOffset = measuredWord->startOffset + measuredWord->length; @@ -2412,7 +2375,7 @@ void Clay__CalculateFinalLayout(void) { // measuredWord->length == 0 means a newline character else if (measuredWord->length == 0 || lineWidth + measuredWord->width > containerElement->dimensions.width) { // Wrapped text lines list has overflowed, just render out the line - Clay__WrappedTextLineArray_Add(&Clay__wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth, lineHeight }, { .length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } }); + Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth, lineHeight }, { .length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } }); textElementData->wrappedLines.length++; if (lineLengthChars == 0 || measuredWord->length == 0) { wordIndex = measuredWord->next; @@ -2427,32 +2390,32 @@ void Clay__CalculateFinalLayout(void) { } } if (lineLengthChars > 0) { - Clay__WrappedTextLineArray_Add(&Clay__wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth, lineHeight }, {.length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } }); + Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth, lineHeight }, {.length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } }); textElementData->wrappedLines.length++; } containerElement->dimensions.height = lineHeight * (float)textElementData->wrappedLines.length; } // Scale vertical image heights according to aspect ratio - for (int32_t i = 0; i < Clay__imageElementPointers.length; ++i) { - Clay_LayoutElement* imageElement = Clay__LayoutElementPointerArray_Get(&Clay__imageElementPointers, i); + for (int32_t i = 0; i < context->imageElementPointers.length; ++i) { + Clay_LayoutElement* imageElement = Clay__LayoutElementPointerArray_Get(&context->imageElementPointers, i); Clay_ImageElementConfig *config = Clay__FindElementConfigWithType(imageElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE).imageElementConfig; imageElement->dimensions.height = (config->sourceDimensions.height / CLAY__MAX(config->sourceDimensions.width, 1)) * imageElement->dimensions.width; } // Propagate effect of text wrapping, image aspect scaling etc. on height of parents - Clay__LayoutElementTreeNodeArray dfsBuffer = Clay__layoutElementTreeNodeArray1; + Clay__LayoutElementTreeNodeArray dfsBuffer = context->layoutElementTreeNodeArray1; dfsBuffer.length = 0; - for (int32_t i = 0; i < Clay__layoutElementTreeRoots.length; ++i) { - Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, i); - Clay__treeNodeVisited.internalArray[dfsBuffer.length] = false; - Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)root->layoutElementIndex) }); + for (int32_t i = 0; i < context->layoutElementTreeRoots.length; ++i) { + Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, i); + context->treeNodeVisited.internalArray[dfsBuffer.length] = false; + Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex) }); } while (dfsBuffer.length > 0) { Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1); Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement; - if (!Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1]) { - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; + if (!context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) { + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; // If the element has no children or is the container for a text element, don't bother inspecting it if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT) || currentElement->childrenOrTextContent.children.length == 0) { dfsBuffer.length--; @@ -2460,8 +2423,8 @@ void Clay__CalculateFinalLayout(void) { } // Add the children to the DFS buffer (needs to be pushed in reverse so that stack traversal is in correct layout order) for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; i++) { - Clay__treeNodeVisited.internalArray[dfsBuffer.length] = false; - Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]) }); + context->treeNodeVisited.internalArray[dfsBuffer.length] = false; + Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]) }); } continue; } @@ -2475,7 +2438,7 @@ void Clay__CalculateFinalLayout(void) { if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { // Resize any parent containers that have grown in height along their non layout axis for (int32_t j = 0; j < currentElement->childrenOrTextContent.children.length; ++j) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[j]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[j]); float childHeightWithPadding = CLAY__MAX(childElement->dimensions.height + layoutConfig->padding.y * 2, currentElement->dimensions.height); currentElement->dimensions.height = CLAY__MIN(CLAY__MAX(childHeightWithPadding, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max); } @@ -2483,7 +2446,7 @@ void Clay__CalculateFinalLayout(void) { // Resizing along the layout axis float contentHeight = (float)layoutConfig->padding.y * 2; for (int32_t j = 0; j < currentElement->childrenOrTextContent.children.length; ++j) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[j]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[j]); contentHeight += childElement->dimensions.height; } contentHeight += (float)(CLAY__MAX(currentElement->childrenOrTextContent.children.length - 1, 0) * layoutConfig->childGap); @@ -2495,12 +2458,12 @@ void Clay__CalculateFinalLayout(void) { Clay__SizeContainersAlongAxis(false); // Calculate final positions and generate render commands - Clay__renderCommands.length = 0; + context->renderCommands.length = 0; dfsBuffer.length = 0; - for (int32_t rootIndex = 0; rootIndex < Clay__layoutElementTreeRoots.length; ++rootIndex) { + for (int32_t rootIndex = 0; rootIndex < context->layoutElementTreeRoots.length; ++rootIndex) { dfsBuffer.length = 0; - Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, rootIndex); - Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)root->layoutElementIndex); + Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex); + Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex); Clay_Vector2 rootPosition = CLAY__DEFAULT_STRUCT; Clay_LayoutElementHashMapItem *parentHashMapItem = Clay__GetHashMapItem(root->parentId); // Position root floating containers @@ -2562,10 +2525,10 @@ void Clay__CalculateFinalLayout(void) { Clay_LayoutElementHashMapItem *clipHashMapItem = Clay__GetHashMapItem(root->clipElementId); if (clipHashMapItem) { // Floating elements that are attached to scrolling contents won't be correctly positioned if external scroll handling is enabled, fix here - if (Clay__externalScrollHandlingEnabled) { + if (context->externalScrollHandlingEnabled) { Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(clipHashMapItem->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig; - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (mapping->layoutElement == clipHashMapItem->layoutElement) { root->pointerOffset = mapping->scrollPosition; if (scrollConfig->horizontal) { @@ -2588,7 +2551,7 @@ void Clay__CalculateFinalLayout(void) { } Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = rootElement, .position = rootPosition, .nextChildOffset = { .x = (float)rootElement->layoutConfig->padding.x, .y = (float)rootElement->layoutConfig->padding.y } }); - Clay__treeNodeVisited.internalArray[0] = false; + context->treeNodeVisited.internalArray[0] = false; while (dfsBuffer.length > 0) { Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1); Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement; @@ -2596,8 +2559,8 @@ void Clay__CalculateFinalLayout(void) { Clay_Vector2 scrollOffset = CLAY__DEFAULT_STRUCT; // This will only be run a single time for each element in downwards DFS order - if (!Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1]) { - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; + if (!context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) { + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; Clay_BoundingBox currentElementBoundingBox = { currentElementTreeNode->position.x, currentElementTreeNode->position.y, currentElement->dimensions.width, currentElement->dimensions.height }; if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER)) { @@ -2615,8 +2578,8 @@ void Clay__CalculateFinalLayout(void) { Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER).scrollElementConfig; // This linear scan could theoretically be slow under very strange conditions, but I can't imagine a real UI with more than a few 10's of scroll containers - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (mapping->layoutElement == currentElement) { scrollContainerData = mapping; mapping->boundingBox = currentElementBoundingBox; @@ -2626,7 +2589,7 @@ void Clay__CalculateFinalLayout(void) { if (scrollConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; } - if (Clay__externalScrollHandlingEnabled) { + if (context->externalScrollHandlingEnabled) { scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT; } break; @@ -2719,7 +2682,7 @@ void Clay__CalculateFinalLayout(void) { }); yPosition += finalLineHeight; - if (!Clay__disableCulling && (currentElementBoundingBox.y + yPosition > Clay__layoutDimensions.height)) { + if (!context->disableCulling && (currentElementBoundingBox.y + yPosition > context->layoutDimensions.height)) { break; } } @@ -2746,7 +2709,7 @@ void Clay__CalculateFinalLayout(void) { Clay_Dimensions contentSize = {0,0}; if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]); contentSize.width += childElement->dimensions.width; contentSize.height = CLAY__MAX(contentSize.height, childElement->dimensions.height); } @@ -2760,7 +2723,7 @@ void Clay__CalculateFinalLayout(void) { currentElementTreeNode->nextChildOffset.x += extraSpace; } else { for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]); contentSize.width = CLAY__MAX(contentSize.width, childElement->dimensions.width); contentSize.height += childElement->dimensions.height; } @@ -2785,12 +2748,12 @@ void Clay__CalculateFinalLayout(void) { 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; - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (mapping->layoutElement == currentElement) { if (scrollConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; } if (scrollConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; } - if (Clay__externalScrollHandlingEnabled) { + if (context->externalScrollHandlingEnabled) { scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT; } break; @@ -2817,7 +2780,7 @@ void Clay__CalculateFinalLayout(void) { Clay_Vector2 borderOffset = { (float)layoutConfig->padding.x, (float)layoutConfig->padding.y }; if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]); if (i > 0) { Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) { .boundingBox = { currentElementBoundingBox.x + borderOffset.x + scrollOffset.x, currentElementBoundingBox.y + scrollOffset.y, (float)borderConfig->betweenChildren.width, currentElement->dimensions.height }, @@ -2830,7 +2793,7 @@ void Clay__CalculateFinalLayout(void) { } } else { for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]); if (i > 0) { Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) { .boundingBox = { currentElementBoundingBox.x + scrollOffset.x, currentElementBoundingBox.y + borderOffset.y + scrollOffset.y, currentElement->dimensions.width, (float)borderConfig->betweenChildren.width }, @@ -2861,7 +2824,7 @@ void Clay__CalculateFinalLayout(void) { if (!Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT)) { dfsBuffer.length += currentElement->childrenOrTextContent.children.length; for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) { - Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, currentElement->childrenOrTextContent.children.elements[i]); + Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]); // Alignment along non layout axis if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { currentElementTreeNode->nextChildOffset.y = currentElement->layoutConfig->padding.y; @@ -2893,7 +2856,7 @@ void Clay__CalculateFinalLayout(void) { .position = { childPosition.x, childPosition.y }, .nextChildOffset = { .x = (float)childElement->layoutConfig->padding.x, .y = (float)childElement->layoutConfig->padding.y }, }; - Clay__treeNodeVisited.internalArray[newNodeIndex] = false; + context->treeNodeVisited.internalArray[newNodeIndex] = false; // Update parent offsets if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) { @@ -2912,37 +2875,40 @@ void Clay__CalculateFinalLayout(void) { } void Clay__AttachId(Clay_ElementId elementId) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); openLayoutElement->id = elementId.id; Clay__AddHashMapItem(elementId, openLayoutElement); - Clay__StringArray_Add(&Clay__layoutElementIdStrings, elementId.stringId); + Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId); } void Clay__AttachLayoutConfig(Clay_LayoutConfig *config) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay__GetOpenLayoutElement()->layoutConfig = config; } void Clay__AttachElementConfig(Clay_ElementConfigUnion config, Clay__ElementConfigType type) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); openLayoutElement->elementConfigs.length++; - Clay__ElementConfigArray_Add(&Clay__elementConfigBuffer, CLAY__INIT(Clay_ElementConfig) { .type = type, .config = config }); + Clay__ElementConfigArray_Add(&context->elementConfigBuffer, CLAY__INIT(Clay_ElementConfig) { .type = type, .config = config }); } -Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY_LAYOUT_DEFAULT : Clay__LayoutConfigArray_Add(&Clay__layoutConfigs, config); } -Clay_RectangleElementConfig * Clay__StoreRectangleElementConfig(Clay_RectangleElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT : Clay__RectangleElementConfigArray_Add(&Clay__rectangleElementConfigs, config); } -Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__TEXT_ELEMENT_CONFIG_DEFAULT : Clay__TextElementConfigArray_Add(&Clay__textElementConfigs, config); } -Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay__imageElementConfigs, config); } -Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay__floatingElementConfigs, config); } -Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay__customElementConfigs, config); } -Clay_ScrollElementConfig * Clay__StoreScrollElementConfig(Clay_ScrollElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT : Clay__ScrollElementConfigArray_Add(&Clay__scrollElementConfigs, config); } -Clay_BorderElementConfig * Clay__StoreBorderElementConfig(Clay_BorderElementConfig config) { return Clay__booleanWarnings.maxElementsExceeded ? &CLAY__BORDER_ELEMENT_CONFIG_DEFAULT : Clay__BorderElementConfigArray_Add(&Clay__borderElementConfigs, config); } +Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY_LAYOUT_DEFAULT : Clay__LayoutConfigArray_Add(&Clay_GetCurrentContext()->layoutConfigs, config); } +Clay_RectangleElementConfig * Clay__StoreRectangleElementConfig(Clay_RectangleElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT : Clay__RectangleElementConfigArray_Add(&Clay_GetCurrentContext()->rectangleElementConfigs, config); } +Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__TEXT_ELEMENT_CONFIG_DEFAULT : Clay__TextElementConfigArray_Add(&Clay_GetCurrentContext()->textElementConfigs, config); } +Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay_GetCurrentContext()->imageElementConfigs, config); } +Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay_GetCurrentContext()->floatingElementConfigs, config); } +Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay_GetCurrentContext()->customElementConfigs, config); } +Clay_ScrollElementConfig * Clay__StoreScrollElementConfig(Clay_ScrollElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT : Clay__ScrollElementConfigArray_Add(&Clay_GetCurrentContext()->scrollElementConfigs, config); } +Clay_BorderElementConfig * Clay__StoreBorderElementConfig(Clay_BorderElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY__BORDER_ELEMENT_CONFIG_DEFAULT : Clay__BorderElementConfigArray_Add(&Clay_GetCurrentContext()->borderElementConfigs, config); } #pragma region DebugTools Clay_Color CLAY__DEBUGVIEW_COLOR_1 = {58, 56, 52, 255}; @@ -2982,7 +2948,8 @@ CLAY__TYPEDEF(Clay__RenderDebugLayoutData, struct { // Returns row count Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialRootsLength, int32_t highlightedRowIndex) { - Clay__int32_tArray dfsBuffer = Clay__reusableElementIndexBuffer; + Clay_Context* context = Clay_GetCurrentContext(); + Clay__int32_tArray dfsBuffer = context->reusableElementIndexBuffer; Clay__DebugView_ScrollViewItemLayoutConfig = CLAY__INIT(Clay_LayoutConfig) { .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT) }, .childGap = 6, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }}; Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT; @@ -2990,19 +2957,19 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR for (int32_t rootIndex = 0; rootIndex < initialRootsLength; ++rootIndex) { dfsBuffer.length = 0; - Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, rootIndex); + Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex); Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex); - Clay__treeNodeVisited.internalArray[0] = false; + context->treeNodeVisited.internalArray[0] = false; if (rootIndex > 0) { - CLAY(CLAY_IDI("Clay__DebugView_EmptyRowOuter", rootIndex), CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .padding = {CLAY__DEBUGVIEW_INDENT_WIDTH / 2, 0} })) { - CLAY(CLAY_IDI("Clay__DebugView_EmptyRow", rootIndex), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .height = CLAY_SIZING_FIXED((float)CLAY__DEBUGVIEW_ROW_HEIGHT) }}), CLAY_BORDER({ .top = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 } })) {} + CLAY(CLAY_IDI("Clay__DebugView_EmptyRowOuter", rootIndex), CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(0)}, .padding = {CLAY__DEBUGVIEW_INDENT_WIDTH / 2, 0} })) { + CLAY(CLAY_IDI("Clay__DebugView_EmptyRow", rootIndex), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED((float)CLAY__DEBUGVIEW_ROW_HEIGHT) }}), CLAY_BORDER({ .top = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 } })) {} } layoutData.rowCount++; } while (dfsBuffer.length > 0) { int32_t currentElementIndex = Clay__int32_tArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1); - Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)currentElementIndex); - if (Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1]) { + Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)currentElementIndex); + if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) { if (!Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT) && currentElement->childrenOrTextContent.children.length > 0) { Clay__CloseElement(); Clay__CloseElement(); @@ -3013,16 +2980,16 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR } if (highlightedRowIndex == layoutData.rowCount) { - if (Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { - Clay__debugSelectedElementId = currentElement->id; + if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + context->debugSelectedElementId = currentElement->id; } highlightedElementId = currentElement->id; } - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; Clay_LayoutElementHashMapItem *currentElementData = Clay__GetHashMapItem(currentElement->id); bool offscreen = Clay__ElementIsOffscreen(¤tElementData->boundingBox); - if (Clay__debugSelectedElementId == currentElement->id) { + if (context->debugSelectedElementId == currentElement->id) { layoutData.selectedElementRowIndex = layoutData.rowCount; } CLAY(CLAY_IDI("Clay__DebugView_ElementOuter", currentElement->id), Clay__AttachLayoutConfig(&Clay__DebugView_ScrollViewItemLayoutConfig)) { @@ -3052,7 +3019,7 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR } } } - Clay_String idString = Clay__layoutElementIdStrings.internalArray[currentElementIndex]; + Clay_String idString = context->layoutElementIdStrings.internalArray[currentElementIndex]; if (idString.length > 0) { CLAY_TEXT(idString, offscreen ? CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 }) : &Clay__DebugView_TextNameConfig); } @@ -3098,16 +3065,16 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR if (!(Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT) || (currentElementData && currentElementData->debugData->collapsed))) { for (int32_t i = currentElement->childrenOrTextContent.children.length - 1; i >= 0; --i) { Clay__int32_tArray_Add(&dfsBuffer, currentElement->childrenOrTextContent.children.elements[i]); - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked } } } } - if (Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { Clay_ElementId collapseButtonId = Clay__HashString(CLAY_STRING("Clay__DebugView_CollapseElement"), 0, 0); - for (int32_t i = (int)Clay__pointerOverIds.length - 1; i >= 0; i--) { - Clay_ElementId *elementId = Clay__ElementIdArray_Get(&Clay__pointerOverIds, i); + for (int32_t i = (int)context->pointerOverIds.length - 1; i >= 0; i--) { + Clay_ElementId *elementId = Clay__ElementIdArray_Get(&context->pointerOverIds, i); if (elementId->baseId == collapseButtonId.baseId) { Clay_LayoutElementHashMapItem *highlightedItem = Clay__GetHashMapItem(elementId->offset); highlightedItem->debugData->collapsed = !highlightedItem->debugData->collapsed; @@ -3117,8 +3084,8 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR } if (highlightedElementId) { - CLAY(CLAY_ID("Clay__DebugView_ElementHighlight"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_FLOATING({ .zIndex = 65535, .parentId = highlightedElementId })) { - CLAY(CLAY_ID("Clay__DebugView_ElementHighlightRectangle"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_RECTANGLE({.color = Clay__debugViewHighlightColor })) {} + CLAY(CLAY_ID("Clay__DebugView_ElementHighlight"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }), CLAY_FLOATING({ .zIndex = 65535, .parentId = highlightedElementId })) { + CLAY(CLAY_ID("Clay__DebugView_ElementHighlightRectangle"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }), CLAY_RECTANGLE({.color = Clay__debugViewHighlightColor })) {} } } return layoutData; @@ -3153,11 +3120,11 @@ void Clay__RenderDebugViewElementConfigHeader(Clay_String elementId, Clay__Eleme Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(type); Clay_Color backgroundColor = config.color; backgroundColor.a = 90; - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = { .x = CLAY__DEBUGVIEW_OUTER_PADDING }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } })) { + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = { .x = 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 = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT) } })) {} + CLAY(CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) } })) {} CLAY_TEXT(elementId, CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE })); } } @@ -3206,54 +3173,56 @@ void Clay__RenderDebugViewBorder(int32_t index, Clay_Border border, Clay_TextEle } void HandleDebugViewCloseButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerInfo, intptr_t userData) { + Clay_Context* context = Clay_GetCurrentContext(); (void) elementId; (void) pointerInfo; (void) userData; if (pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { - Clay__debugModeEnabled = false; + context->debugModeEnabled = false; } } -void Clay__RenderDebugView(void) { +void Clay__RenderDebugView() { + Clay_Context* context = Clay_GetCurrentContext(); Clay_ElementId closeButtonId = Clay__HashString(CLAY_STRING("Clay__DebugViewTopHeaderCloseButtonOuter"), 0, 0); - if (Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { - for (int32_t i = 0; i < Clay__pointerOverIds.length; ++i) { - Clay_ElementId *elementId = Clay__ElementIdArray_Get(&Clay__pointerOverIds, i); + if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + for (int32_t i = 0; i < context->pointerOverIds.length; ++i) { + Clay_ElementId *elementId = Clay__ElementIdArray_Get(&context->pointerOverIds, i); if (elementId->id == closeButtonId.id) { - Clay__debugModeEnabled = false; + context->debugModeEnabled = false; return; } } } - uint32_t initialRootsLength = Clay__layoutElementTreeRoots.length; - uint32_t initialElementsLength = Clay__layoutElements.length; + uint32_t initialRootsLength = context->layoutElementTreeRoots.length; + uint32_t initialElementsLength = context->layoutElements.length; Clay_TextElementConfig *infoTextConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }); Clay_TextElementConfig *infoTitleConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }); Clay_ElementId scrollId = Clay__HashString(CLAY_STRING("Clay__DebugViewOuterScrollPane"), 0, 0); float scrollYOffset = 0; - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; ++i) { - Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; ++i) { + Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (scrollContainerData->elementId == scrollId.id) { - if (!Clay__externalScrollHandlingEnabled) { + if (!context->externalScrollHandlingEnabled) { scrollYOffset = scrollContainerData->scrollPosition.y; } break; } } - int32_t highlightedRow = Clay__pointerInfo.position.y < Clay__layoutDimensions.height - 300 - ? (int32_t)((Clay__pointerInfo.position.y - scrollYOffset) / (float)CLAY__DEBUGVIEW_ROW_HEIGHT) - 1 + int32_t highlightedRow = context->pointerInfo.position.y < context->layoutDimensions.height - 300 + ? (int32_t)((context->pointerInfo.position.y - scrollYOffset) / (float)CLAY__DEBUGVIEW_ROW_HEIGHT) - 1 : -1; - if (Clay__pointerInfo.position.x < Clay__layoutDimensions.width - (float)Clay__debugViewWidth) { + if (context->pointerInfo.position.x < context->layoutDimensions.width - (float)Clay__debugViewWidth) { highlightedRow = -1; } Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT; CLAY(CLAY_ID("Clay__DebugView"), CLAY_FLOATING({ .parentId = Clay__HashString(CLAY_STRING("Clay__RootContainer"), 0, 0).id, .attachment = { .element = CLAY_ATTACH_POINT_LEFT_CENTER, .parent = CLAY_ATTACH_POINT_RIGHT_CENTER }}), - CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED((float)Clay__debugViewWidth) , CLAY_SIZING_FIXED(Clay__layoutDimensions.height) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }), + CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED((float)Clay__debugViewWidth) , CLAY_SIZING_FIXED(context->layoutDimensions.height) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_BORDER({ .bottom = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 }}) ) { - CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) { + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) { CLAY_TEXT(CLAY_STRING("Clay Debug Tools"), infoTextConfig); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY__DEFAULT_STRUCT } })) {} + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), {0} } })) {} // Close button CLAY(CLAY_BORDER_OUTSIDE_RADIUS(1, (CLAY__INIT(Clay_Color){217,91,67,255}), 4), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 10), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 10)}, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER} }), @@ -3263,13 +3232,13 @@ void Clay__RenderDebugView(void) { CLAY_TEXT(CLAY_STRING("x"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 })); } } - CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {} - CLAY(Clay__AttachId(scrollId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_SCROLL({ .horizontal = true, .vertical = true })) { - CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 })) { + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {} + CLAY(Clay__AttachId(scrollId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }), CLAY_SCROLL({ .horizontal = true, .vertical = true })) { + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 })) { Clay_ElementId panelContentsId = Clay__HashString(CLAY_STRING("Clay__DebugViewPaneOuter"), 0, 0); // Element list - CLAY(Clay__AttachId(panelContentsId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_FLOATING({ .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH })) { - CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .padding = {.x = CLAY__DEBUGVIEW_OUTER_PADDING }, .layoutDirection = CLAY_TOP_TO_BOTTOM })) { + CLAY(Clay__AttachId(panelContentsId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }), CLAY_FLOATING({ .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH })) { + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .padding = {.x = CLAY__DEBUGVIEW_OUTER_PADDING }, .layoutDirection = CLAY_TOP_TO_BOTTOM })) { layoutData = Clay__RenderDebugLayoutElementsList((int32_t)initialRootsLength, highlightedRow); } } @@ -3285,22 +3254,22 @@ void Clay__RenderDebugView(void) { rowColor.g *= 1.25f; rowColor.b *= 1.25f; } - CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = rowColor })) {} + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = rowColor })) {} } } } - CLAY(CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .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_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {} + if (context->debugSelectedElementId != 0) { + Clay_LayoutElementHashMapItem *selectedItem = Clay__GetHashMapItem(context->debugSelectedElementId); CLAY( CLAY_SCROLL({ .vertical = true }), - CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), + CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), 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__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) { + CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) { CLAY_TEXT(CLAY_STRING("Layout Config"), infoTextConfig); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY__DEFAULT_STRUCT } })) {} + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), {0} } })) {} if (selectedItem->elementId.stringId.length != 0) { CLAY_TEXT(selectedItem->elementId.stringId, infoTitleConfig); if (selectedItem->elementId.offset != 0) { @@ -3433,7 +3402,7 @@ void Clay__RenderDebugView(void) { } // Image Preview CLAY_TEXT(CLAY_STRING("Preview"), infoTitleConfig); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = imageConfig->sourceDimensions.width }), CLAY__DEFAULT_STRUCT }}), Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = imageConfig }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) {} + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0, imageConfig->sourceDimensions.width), {0} }}), Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = imageConfig }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) {} } break; } @@ -3510,15 +3479,15 @@ void Clay__RenderDebugView(void) { } } } else { - CLAY(CLAY_ID("Clay__DebugViewWarningsScrollPane"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_SCROLL({ .horizontal = true, .vertical = true }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) { + CLAY(CLAY_ID("Clay__DebugViewWarningsScrollPane"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_SCROLL({ .horizontal = true, .vertical = true }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) { Clay_TextElementConfig *warningConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }); CLAY(CLAY_ID("Clay__DebugViewWarningItemHeader"), CLAY_LAYOUT({ .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) { CLAY_TEXT(CLAY_STRING("Warnings"), warningConfig); } - CLAY(CLAY_ID("Clay__DebugViewWarningsTopBorder"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = {200, 200, 200, 255} })) {} - int32_t previousWarningsLength = (int)Clay_warnings.length; + CLAY(CLAY_ID("Clay__DebugViewWarningsTopBorder"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = {200, 200, 200, 255} })) {} + int32_t previousWarningsLength = context->warnings.length; for (int32_t i = 0; i < previousWarningsLength; i++) { - Clay__Warning warning = Clay_warnings.internalArray[i]; + Clay__Warning warning = context->warnings.internalArray[i]; CLAY(CLAY_IDI("Clay__DebugViewWarningItem", i), CLAY_LAYOUT({ .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) { CLAY_TEXT(warning.baseMessage, warningConfig); if (warning.dynamicMessage.length > 0) { @@ -3532,14 +3501,104 @@ void Clay__RenderDebugView(void) { } #pragma endregion +uint32_t Clay__debugViewWidth = 400; +Clay_Color Clay__debugViewHighlightColor = { 168, 66, 28, 100 }; + +Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Arena *arena) { + size_t totalSizeBytes = capacity * sizeof(Clay_String); + Clay__WarningArray array = {.capacity = capacity, .length = 0}; + uintptr_t nextAllocAddress = arena->nextAllocation + (uintptr_t)arena->memory; + uintptr_t arenaOffsetAligned = nextAllocAddress + (CLAY__ALIGNMENT(Clay_String) - (nextAllocAddress % CLAY__ALIGNMENT(Clay_String))); + arenaOffsetAligned -= (uintptr_t)arena->memory; + if (arenaOffsetAligned + totalSizeBytes <= arena->capacity) { + array.internalArray = (Clay__Warning*)((uintptr_t)arena->memory + (uintptr_t)arenaOffsetAligned); + arena->nextAllocation = arenaOffsetAligned + totalSizeBytes; + } + else { + Clay__currentContext->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED, + .errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"), + .userData = Clay__currentContext->errorHandler.userData }); + } + return array; +} + +Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item) +{ + if (array->length < array->capacity) { + array->internalArray[array->length++] = item; + return &array->internalArray[array->length - 1]; + } + return &CLAY__WARNING_DEFAULT; +} + +void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, uint32_t alignment, Clay_Arena *arena) +{ + size_t totalSizeBytes = capacity * itemSize; + uintptr_t nextAllocAddress = arena->nextAllocation + (uintptr_t)arena->memory; + uintptr_t arenaOffsetAligned = nextAllocAddress + (alignment - (nextAllocAddress % alignment)); + arenaOffsetAligned -= (uintptr_t)arena->memory; + if (arenaOffsetAligned + totalSizeBytes <= arena->capacity) { + arena->nextAllocation = arenaOffsetAligned + totalSizeBytes; + return (void*)((uintptr_t)arena->memory + (uintptr_t)arenaOffsetAligned); + } + else { + Clay__currentContext->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED, + .errorText = CLAY_STRING("Clay attempted to allocate memory in its arena, but ran out of capacity. Try increasing the capacity of the arena passed to Clay_Initialize()"), + .userData = Clay__currentContext->errorHandler.userData }); + } + return CLAY__NULL; +} + +bool Clay__Array_RangeCheck(int32_t index, int32_t length) +{ + if (index < length && index >= 0) { + return true; + } + Clay_Context* context = Clay_GetCurrentContext(); + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR, + .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."), + .userData = context->errorHandler.userData }); + return false; +} + +bool Clay__Array_AddCapacityCheck(int32_t length, int32_t capacity) +{ + if (length < capacity) { + return true; + } + Clay_Context* context = Clay_GetCurrentContext(); + context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) { + .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR, + .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."), + .userData = context->errorHandler.userData }); + return false; +} + // PUBLIC API FROM HERE --------------------------------------- CLAY_WASM_EXPORT("Clay_MinMemorySize") uint32_t Clay_MinMemorySize(void) { - Clay_Arena fakeArena = { .capacity = SIZE_MAX }; - Clay__InitializePersistentMemory(&fakeArena); - Clay__InitializeEphemeralMemory(&fakeArena); - return fakeArena.nextAllocation; + Clay_Context fakeContext = { + .maxElementCount = Clay__defaultMaxElementCount, + .maxMeasureTextCacheWordCount = Clay__defaultMaxMeasureTextWordCacheCount, + .internalArena = { + .capacity = SIZE_MAX, + .memory = (char*)&fakeContext, + } + }; + Clay_Context* currentContext = Clay_GetCurrentContext(); + if (currentContext) { + fakeContext.maxElementCount = currentContext->maxElementCount; + fakeContext.maxMeasureTextCacheWordCount = currentContext->maxElementCount; + } + // Reserve space in the arena for the context, important for calculating min memory size correctly + Clay__Context_Allocate_Arena(&fakeContext.internalArena); + Clay__InitializePersistentMemory(&fakeContext); + Clay__InitializeEphemeralMemory(&fakeContext); + return fakeContext.internalArena.nextAllocation; } CLAY_WASM_EXPORT("Clay_CreateArenaWithCapacityAndMemory") @@ -3562,30 +3621,31 @@ void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction) CLAY_WASM_EXPORT("Clay_SetLayoutDimensions") void Clay_SetLayoutDimensions(Clay_Dimensions dimensions) { - Clay__layoutDimensions = dimensions; + Clay_GetCurrentContext()->layoutDimensions = dimensions; } CLAY_WASM_EXPORT("Clay_SetPointerState") void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } - Clay__pointerInfo.position = position; - Clay__pointerOverIds.length = 0; - Clay__int32_tArray dfsBuffer = Clay__layoutElementChildrenBuffer; - for (int32_t rootIndex = Clay__layoutElementTreeRoots.length - 1; rootIndex >= 0; --rootIndex) { + context->pointerInfo.position = position; + context->pointerOverIds.length = 0; + Clay__int32_tArray dfsBuffer = context->layoutElementChildrenBuffer; + for (int32_t rootIndex = context->layoutElementTreeRoots.length - 1; rootIndex >= 0; --rootIndex) { dfsBuffer.length = 0; - Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, rootIndex); + Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex); Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex); - Clay__treeNodeVisited.internalArray[0] = false; + context->treeNodeVisited.internalArray[0] = false; bool found = false; while (dfsBuffer.length > 0) { - if (Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1]) { + if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) { dfsBuffer.length--; continue; } - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; - Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, Clay__int32_tArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1)); + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; + Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_Get(&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 Clay_BoundingBox elementBox = mapItem->boundingBox; elementBox.x -= root->pointerOffset.x; @@ -3593,9 +3653,9 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) { if (mapItem) { if ((Clay__PointIsInsideRect(position, elementBox))) { if (mapItem->onHoverFunction) { - mapItem->onHoverFunction(mapItem->elementId, Clay__pointerInfo, mapItem->hoverFunctionUserData); + mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData); } - Clay__ElementIdArray_Add(&Clay__pointerOverIds, mapItem->elementId); + Clay__ElementIdArray_Add(&context->pointerOverIds, mapItem->elementId); found = true; } if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT)) { @@ -3604,14 +3664,14 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) { } for (int32_t i = currentElement->childrenOrTextContent.children.length - 1; i >= 0; --i) { Clay__int32_tArray_Add(&dfsBuffer, currentElement->childrenOrTextContent.children.elements[i]); - Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked + context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked } } else { dfsBuffer.length--; } } - Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, root->layoutElementIndex); + Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, root->layoutElementIndex); if (found && Clay__ElementHasConfig(rootElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER) && Clay__FindElementConfigWithType(rootElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER).floatingElementConfig->pointerCaptureMode == CLAY_POINTER_CAPTURE_MODE_CAPTURE) { break; @@ -3619,55 +3679,75 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) { } if (isPointerDown) { - if (Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { - Clay__pointerInfo.state = CLAY_POINTER_DATA_PRESSED; - } else if (Clay__pointerInfo.state != CLAY_POINTER_DATA_PRESSED) { - Clay__pointerInfo.state = CLAY_POINTER_DATA_PRESSED_THIS_FRAME; + if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + context->pointerInfo.state = CLAY_POINTER_DATA_PRESSED; + } else if (context->pointerInfo.state != CLAY_POINTER_DATA_PRESSED) { + context->pointerInfo.state = CLAY_POINTER_DATA_PRESSED_THIS_FRAME; } } else { - if (Clay__pointerInfo.state == CLAY_POINTER_DATA_RELEASED_THIS_FRAME) { - Clay__pointerInfo.state = CLAY_POINTER_DATA_RELEASED; - } else if (Clay__pointerInfo.state != CLAY_POINTER_DATA_RELEASED) { - Clay__pointerInfo.state = CLAY_POINTER_DATA_RELEASED_THIS_FRAME; + if (context->pointerInfo.state == CLAY_POINTER_DATA_RELEASED_THIS_FRAME) { + context->pointerInfo.state = CLAY_POINTER_DATA_RELEASED; + } else if (context->pointerInfo.state != CLAY_POINTER_DATA_RELEASED) { + context->pointerInfo.state = CLAY_POINTER_DATA_RELEASED_THIS_FRAME; } } } CLAY_WASM_EXPORT("Clay_Initialize") -void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) { - Clay__internalArena = arena; - Clay__InitializePersistentMemory(&Clay__internalArena); - Clay__InitializeEphemeralMemory(&Clay__internalArena); - for (int32_t i = 0; i < Clay__layoutElementsHashMap.capacity; ++i) { - Clay__layoutElementsHashMap.internalArray[i] = -1; +Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) { + Clay_Context *context = Clay__Context_Allocate_Arena(&arena); + if (context == NULL) return NULL; + // DEFAULTS + Clay_Context *oldContext = Clay_GetCurrentContext(); + *context = CLAY__INIT(Clay_Context) { + .maxElementCount = oldContext ? oldContext->maxElementCount : Clay__defaultMaxElementCount, + .maxMeasureTextCacheWordCount = oldContext ? oldContext->maxMeasureTextCacheWordCount : Clay__defaultMaxElementCount * 2, + .errorHandler = errorHandler.errorHandlerFunction ? errorHandler : CLAY__INIT(Clay_ErrorHandler) { Clay__ErrorHandlerFunctionDefault }, + .layoutDimensions = layoutDimensions, + .internalArena = arena, + }; + Clay_SetCurrentContext(context); + Clay__InitializePersistentMemory(context); + Clay__InitializeEphemeralMemory(context); + for (int32_t i = 0; i < context->layoutElementsHashMap.capacity; ++i) { + context->layoutElementsHashMap.internalArray[i] = -1; } - for (int32_t i = 0; i < Clay__measureTextHashMap.capacity; ++i) { - Clay__measureTextHashMap.internalArray[i] = 0; - } - Clay__measureTextHashMapInternal.length = 1; // Reserve the 0 value to mean "no next element" - Clay__layoutDimensions = layoutDimensions; - if (errorHandler.errorHandlerFunction) { - Clay__errorHandler = errorHandler; + for (int32_t i = 0; i < context->measureTextHashMap.capacity; ++i) { + context->measureTextHashMap.internalArray[i] = 0; } + context->measureTextHashMapInternal.length = 1; // Reserve the 0 value to mean "no next element" + context->layoutDimensions = layoutDimensions; + return context; +} + +CLAY_WASM_EXPORT("Clay_GetCurrentContext") +Clay_Context* Clay_GetCurrentContext(void) { + return Clay__currentContext; +} + +CLAY_WASM_EXPORT("Clay_SetCurrentContext") +void Clay_SetCurrentContext(Clay_Context* context) { + Clay__currentContext = context; } CLAY_WASM_EXPORT("Clay_UpdateScrollContainers") void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime) { - bool isPointerActive = enableDragScrolling && (Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED || Clay__pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME); + Clay_Context* context = Clay_GetCurrentContext(); + bool isPointerActive = enableDragScrolling && (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED || context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME); // Don't apply scroll events to ancestors of the inner element int32_t highestPriorityElementIndex = -1; Clay__ScrollContainerDataInternal *highestPriorityScrollData = CLAY__NULL; - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *scrollData = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *scrollData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (!scrollData->openThisFrame) { - Clay__ScrollContainerDataInternalArray_RemoveSwapback(&Clay__scrollContainerDatas, i); + Clay__ScrollContainerDataInternalArray_RemoveSwapback(&context->scrollContainerDatas, i); continue; } scrollData->openThisFrame = false; Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(scrollData->elementId); // Element isn't rendered this frame but scroll offset has been retained if (!hashMapItem) { - Clay__ScrollContainerDataInternalArray_RemoveSwapback(&Clay__scrollContainerDatas, i); + Clay__ScrollContainerDataInternalArray_RemoveSwapback(&context->scrollContainerDatas, i); continue; } @@ -3704,8 +3784,8 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe } scrollData->scrollPosition.y = CLAY__MIN(CLAY__MAX(scrollData->scrollPosition.y, -(CLAY__MAX(scrollData->contentSize.height - scrollData->layoutElement->dimensions.height, 0))), 0); - for (int32_t j = 0; j < Clay__pointerOverIds.length; ++j) { // TODO n & m are small here but this being n*m gives me the creeps - if (scrollData->layoutElement->id == Clay__ElementIdArray_Get(&Clay__pointerOverIds, j)->id) { + for (int32_t j = 0; j < context->pointerOverIds.length; ++j) { // TODO n & m are small here but this being n*m gives me the creeps + if (scrollData->layoutElement->id == Clay__ElementIdArray_Get(&context->pointerOverIds, j)->id) { highestPriorityElementIndex = j; highestPriorityScrollData = scrollData; } @@ -3728,26 +3808,26 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe if (isPointerActive) { highestPriorityScrollData->scrollMomentum = CLAY__INIT(Clay_Vector2)CLAY__DEFAULT_STRUCT; if (!highestPriorityScrollData->pointerScrollActive) { - highestPriorityScrollData->pointerOrigin = Clay__pointerInfo.position; + highestPriorityScrollData->pointerOrigin = context->pointerInfo.position; highestPriorityScrollData->scrollOrigin = highestPriorityScrollData->scrollPosition; highestPriorityScrollData->pointerScrollActive = true; } else { float scrollDeltaX = 0, scrollDeltaY = 0; if (canScrollHorizontally) { float oldXScrollPosition = highestPriorityScrollData->scrollPosition.x; - highestPriorityScrollData->scrollPosition.x = highestPriorityScrollData->scrollOrigin.x + (Clay__pointerInfo.position.x - highestPriorityScrollData->pointerOrigin.x); + highestPriorityScrollData->scrollPosition.x = highestPriorityScrollData->scrollOrigin.x + (context->pointerInfo.position.x - highestPriorityScrollData->pointerOrigin.x); highestPriorityScrollData->scrollPosition.x = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.x, 0), -(highestPriorityScrollData->contentSize.width - highestPriorityScrollData->boundingBox.width)); scrollDeltaX = highestPriorityScrollData->scrollPosition.x - oldXScrollPosition; } if (canScrollVertically) { float oldYScrollPosition = highestPriorityScrollData->scrollPosition.y; - highestPriorityScrollData->scrollPosition.y = highestPriorityScrollData->scrollOrigin.y + (Clay__pointerInfo.position.y - highestPriorityScrollData->pointerOrigin.y); + highestPriorityScrollData->scrollPosition.y = highestPriorityScrollData->scrollOrigin.y + (context->pointerInfo.position.y - highestPriorityScrollData->pointerOrigin.y); highestPriorityScrollData->scrollPosition.y = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.y, 0), -(highestPriorityScrollData->contentSize.height - highestPriorityScrollData->boundingBox.height)); scrollDeltaY = highestPriorityScrollData->scrollPosition.y - oldYScrollPosition; } if (scrollDeltaX > -0.1f && scrollDeltaX < 0.1f && scrollDeltaY > -0.1f && scrollDeltaY < 0.1f && highestPriorityScrollData->momentumTime > 0.15f) { highestPriorityScrollData->momentumTime = 0; - highestPriorityScrollData->pointerOrigin = Clay__pointerInfo.position; + highestPriorityScrollData->pointerOrigin = context->pointerInfo.position; highestPriorityScrollData->scrollOrigin = highestPriorityScrollData->scrollPosition; } else { highestPriorityScrollData->momentumTime += deltaTime; @@ -3766,41 +3846,43 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe CLAY_WASM_EXPORT("Clay_BeginLayout") void Clay_BeginLayout(void) { - Clay__InitializeEphemeralMemory(&Clay__internalArena); - Clay__generation++; - Clay__dynamicElementIndex = 0; + Clay_Context* context = Clay_GetCurrentContext(); + Clay__InitializeEphemeralMemory(context); + context->generation++; + context->dynamicElementIndex = 0; // Set up the root container that covers the entire window - Clay_Dimensions rootDimensions = {Clay__layoutDimensions.width, Clay__layoutDimensions.height}; - if (Clay__debugModeEnabled) { + Clay_Dimensions rootDimensions = {context->layoutDimensions.width, context->layoutDimensions.height}; + if (context->debugModeEnabled) { rootDimensions.width -= (float)Clay__debugViewWidth; } - Clay__booleanWarnings.maxElementsExceeded = false; - Clay__booleanWarnings.maxTextMeasureCacheExceeded = false; - Clay__booleanWarnings.maxRenderCommandsExceeded = false; + context->booleanWarnings.maxElementsExceeded = false; + context->booleanWarnings.maxTextMeasureCacheExceeded = false; + context->booleanWarnings.maxRenderCommandsExceeded = false; Clay__OpenElement(); CLAY_ID("Clay__RootContainer"); CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED((rootDimensions.width)), CLAY_SIZING_FIXED(rootDimensions.height)} }); Clay__ElementPostConfiguration(); - Clay__int32_tArray_Add(&Clay__openLayoutElementStack, 0); - Clay__LayoutElementTreeRootArray_Add(&Clay__layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) { .layoutElementIndex = 0 }); + Clay__int32_tArray_Add(&context->openLayoutElementStack, 0); + Clay__LayoutElementTreeRootArray_Add(&context->layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) { .layoutElementIndex = 0 }); } Clay_TextElementConfig Clay__DebugView_ErrorTextConfig = {.textColor = {255, 0, 0, 255}, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }; CLAY_WASM_EXPORT("Clay_EndLayout") -Clay_RenderCommandArray Clay_EndLayout(void) { +Clay_RenderCommandArray Clay_EndLayout() { + Clay_Context* context = Clay_GetCurrentContext(); Clay__CloseElement(); - if (Clay__debugModeEnabled) { - Clay__warningsEnabled = false; + if (context->debugModeEnabled) { + context->warningsEnabled = false; Clay__RenderDebugView(); - Clay__warningsEnabled = true; + context->warningsEnabled = true; } - if (Clay__booleanWarnings.maxElementsExceeded) { - Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) { .boundingBox = { Clay__layoutDimensions.width / 2 - 59 * 4, Clay__layoutDimensions.height / 2, 0, 0 }, .config = { .textElementConfig = &Clay__DebugView_ErrorTextConfig }, .text = CLAY_STRING("Clay Error: Layout elements exceeded Clay__maxElementCount"), .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT }); + if (context->booleanWarnings.maxElementsExceeded) { + Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) { .boundingBox = { context->layoutDimensions.width / 2 - 59 * 4, context->layoutDimensions.height / 2, 0, 0 }, .config = { .textElementConfig = &Clay__DebugView_ErrorTextConfig }, .text = CLAY_STRING("Clay Error: Layout elements exceeded Clay__maxElementCount"), .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT }); } else { Clay__CalculateFinalLayout(); } - return Clay__renderCommands; + return context->renderCommands; } CLAY_WASM_EXPORT("Clay_GetElementId") @@ -3814,7 +3896,8 @@ Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index) } bool Clay_Hovered(void) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return false; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); @@ -3822,8 +3905,8 @@ bool Clay_Hovered(void) { if (openLayoutElement->id == 0) { Clay__GenerateIdForAnonymousElement(openLayoutElement); } - for (int32_t i = 0; i < Clay__pointerOverIds.length; ++i) { - if (Clay__ElementIdArray_Get(&Clay__pointerOverIds, i)->id == openLayoutElement->id) { + for (int32_t i = 0; i < context->pointerOverIds.length; ++i) { + if (Clay__ElementIdArray_Get(&context->pointerOverIds, i)->id == openLayoutElement->id) { return true; } } @@ -3831,7 +3914,8 @@ bool Clay_Hovered(void) { } void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerInfo, intptr_t userData), intptr_t userData) { - if (Clay__booleanWarnings.maxElementsExceeded) { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { return; } Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); @@ -3845,8 +3929,9 @@ void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_Pointer CLAY_WASM_EXPORT("Clay_PointerOver") bool Clay_PointerOver(Clay_ElementId elementId) { // TODO return priority for separating multiple results - for (int32_t i = 0; i < Clay__pointerOverIds.length; ++i) { - if (Clay__ElementIdArray_Get(&Clay__pointerOverIds, i)->id == elementId.id) { + Clay_Context* context = Clay_GetCurrentContext(); + for (int32_t i = 0; i < context->pointerOverIds.length; ++i) { + if (Clay__ElementIdArray_Get(&context->pointerOverIds, i)->id == elementId.id) { return true; } } @@ -3855,8 +3940,9 @@ bool Clay_PointerOver(Clay_ElementId elementId) { // TODO return priority for se CLAY_WASM_EXPORT("Clay_GetScrollContainerData") Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id) { - for (int32_t i = 0; i < Clay__scrollContainerDatas.length; ++i) { - Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&Clay__scrollContainerDatas, i); + Clay_Context* context = Clay_GetCurrentContext(); + for (int32_t i = 0; i < context->scrollContainerDatas.length; ++i) { + Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (scrollContainerData->elementId == id.id) { return CLAY__INIT(Clay_ScrollContainerData) { .scrollPosition = &scrollContainerData->scrollPosition, @@ -3872,32 +3958,58 @@ Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id) { CLAY_WASM_EXPORT("Clay_SetDebugModeEnabled") void Clay_SetDebugModeEnabled(bool enabled) { - Clay__debugModeEnabled = enabled; + Clay_Context* context = Clay_GetCurrentContext(); + context->debugModeEnabled = enabled; } CLAY_WASM_EXPORT("Clay_IsDebugModeEnabled") bool Clay_IsDebugModeEnabled(void) { - return Clay__debugModeEnabled; + Clay_Context* context = Clay_GetCurrentContext(); + return context->debugModeEnabled; } CLAY_WASM_EXPORT("Clay_SetCullingEnabled") void Clay_SetCullingEnabled(bool enabled) { - Clay__disableCulling = !enabled; + Clay_Context* context = Clay_GetCurrentContext(); + context->disableCulling = !enabled; } CLAY_WASM_EXPORT("Clay_SetExternalScrollHandlingEnabled") void Clay_SetExternalScrollHandlingEnabled(bool enabled) { - Clay__externalScrollHandlingEnabled = enabled; + Clay_Context* context = Clay_GetCurrentContext(); + context->externalScrollHandlingEnabled = enabled; +} + +CLAY_WASM_EXPORT("Clay_GetMaxElementCount") +int32_t Clay_GetMaxElementCount(void) { + Clay_Context* context = Clay_GetCurrentContext(); + return context->maxElementCount; } CLAY_WASM_EXPORT("Clay_SetMaxElementCount") void Clay_SetMaxElementCount(int32_t maxElementCount) { - Clay__maxElementCount = maxElementCount; + Clay_Context* context = Clay_GetCurrentContext(); + if (context) { + context->maxElementCount = maxElementCount; + } else { + Clay__defaultMaxElementCount = maxElementCount; // TODO: Fix this + } +} + +CLAY_WASM_EXPORT("Clay_GetMaxMeasureTextCacheWordCount") +int32_t Clay_GetMaxMeasureTextCacheWordCount(void) { + Clay_Context* context = Clay_GetCurrentContext(); + return context->maxMeasureTextCacheWordCount; } CLAY_WASM_EXPORT("Clay_SetMaxMeasureTextCacheWordCount") void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount) { - Clay__maxMeasureTextCacheWordCount = maxMeasureTextCacheWordCount; + Clay_Context* context = Clay_GetCurrentContext(); + if (context) { + Clay__currentContext->maxMeasureTextCacheWordCount = maxMeasureTextCacheWordCount; + } else { + Clay__defaultMaxMeasureTextWordCacheCount = maxMeasureTextCacheWordCount; // TODO: Fix this + } } #endif // CLAY_IMPLEMENTATION diff --git a/examples/SDL2-video-demo/CMakeLists.txt b/examples/SDL2-video-demo/CMakeLists.txt index 46ae95c..96d278e 100644 --- a/examples/SDL2-video-demo/CMakeLists.txt +++ b/examples/SDL2-video-demo/CMakeLists.txt @@ -34,8 +34,12 @@ target_link_libraries(SDL2_video_demo PUBLIC SDL2_ttf::SDL2_ttf-static ) -set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") -set(CMAKE_C_FLAGS_RELEASE "-O3") +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG") +else() + set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") + set(CMAKE_C_FLAGS_RELEASE "-O3") +endif() add_custom_command( TARGET SDL2_video_demo POST_BUILD diff --git a/examples/SDL2-video-demo/main.c b/examples/SDL2-video-demo/main.c index ab0e889..3bd2d2a 100644 --- a/examples/SDL2-video-demo/main.c +++ b/examples/SDL2-video-demo/main.c @@ -74,8 +74,8 @@ void HandleSidebarInteraction( static Clay_RenderCommandArray CreateLayout() { Clay_BeginLayout(); Clay_Sizing layoutExpand = { - .width = CLAY_SIZING_GROW(), - .height = CLAY_SIZING_GROW() + .width = CLAY_SIZING_GROW(0), + .height = CLAY_SIZING_GROW(0) }; Clay_RectangleElementConfig contentBackgroundConfig = { @@ -102,7 +102,7 @@ static Clay_RenderCommandArray CreateLayout() { CLAY_LAYOUT({ .sizing = { .height = CLAY_SIZING_FIXED(60), - .width = CLAY_SIZING_GROW() + .width = CLAY_SIZING_GROW(0) }, .padding = { 16 }, .childGap = 16, @@ -164,7 +164,7 @@ static Clay_RenderCommandArray CreateLayout() { } } RenderHeaderButton(CLAY_STRING("Edit")); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {} + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }})) {} RenderHeaderButton(CLAY_STRING("Upload")); RenderHeaderButton(CLAY_STRING("Media")); RenderHeaderButton(CLAY_STRING("Support")); @@ -183,14 +183,14 @@ static Clay_RenderCommandArray CreateLayout() { .childGap = 8, .sizing = { .width = CLAY_SIZING_FIXED(250), - .height = CLAY_SIZING_GROW() + .height = CLAY_SIZING_GROW(0) } }) ) { for (int i = 0; i < documents.length; i++) { Document document = documents.documents[i]; Clay_LayoutConfig sidebarButtonLayout = { - .sizing = { .width = CLAY_SIZING_GROW() }, + .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = { 16, 16 } }; @@ -262,7 +262,7 @@ void HandleClayErrors(Clay_ErrorData errorData) { printf("%s", errorData.errorText.chars); } -int main(void) { +int main(int argc, char *argv[]) { documents.documents = (Document[]) { { .title = CLAY_STRING("Squirrels"), .contents = CLAY_STRING("The Secret Life of Squirrels: Nature's Clever Acrobats\n""Squirrels are often overlooked creatures, dismissed as mere park inhabitants or backyard nuisances. Yet, beneath their fluffy tails and twitching noses lies an intricate world of cunning, agility, and survival tactics that are nothing short of fascinating. As one of the most common mammals in North America, squirrels have adapted to a wide range of environments from bustling urban centers to tranquil forests and have developed a variety of unique behaviors that continue to intrigue scientists and nature enthusiasts alike.\n""\n""Master Tree Climbers\n""At the heart of a squirrel's skill set is its impressive ability to navigate trees with ease. Whether they're darting from branch to branch or leaping across wide gaps, squirrels possess an innate talent for acrobatics. Their powerful hind legs, which are longer than their front legs, give them remarkable jumping power. With a tail that acts as a counterbalance, squirrels can leap distances of up to ten times the length of their body, making them some of the best aerial acrobats in the animal kingdom.\n""But it's not just their agility that makes them exceptional climbers. Squirrels' sharp, curved claws allow them to grip tree bark with precision, while the soft pads on their feet provide traction on slippery surfaces. Their ability to run at high speeds and scale vertical trunks with ease is a testament to the evolutionary adaptations that have made them so successful in their arboreal habitats.\n""\n""Food Hoarders Extraordinaire\n""Squirrels are often seen frantically gathering nuts, seeds, and even fungi in preparation for winter. While this behavior may seem like instinctual hoarding, it is actually a survival strategy that has been honed over millions of years. Known as \"scatter hoarding,\" squirrels store their food in a variety of hidden locations, often burying it deep in the soil or stashing it in hollowed-out tree trunks.\n""Interestingly, squirrels have an incredible memory for the locations of their caches. Research has shown that they can remember thousands of hiding spots, often returning to them months later when food is scarce. However, they don't always recover every stash some forgotten caches eventually sprout into new trees, contributing to forest regeneration. This unintentional role as forest gardeners highlights the ecological importance of squirrels in their ecosystems.\n""\n""The Great Squirrel Debate: Urban vs. Wild\n""While squirrels are most commonly associated with rural or wooded areas, their adaptability has allowed them to thrive in urban environments as well. In cities, squirrels have become adept at finding food sources in places like parks, streets, and even garbage cans. However, their urban counterparts face unique challenges, including traffic, predators, and the lack of natural shelters. Despite these obstacles, squirrels in urban areas are often observed using human infrastructure such as buildings, bridges, and power lines as highways for their acrobatic escapades.\n""There is, however, a growing concern regarding the impact of urban life on squirrel populations. Pollution, deforestation, and the loss of natural habitats are making it more difficult for squirrels to find adequate food and shelter. As a result, conservationists are focusing on creating squirrel-friendly spaces within cities, with the goal of ensuring these resourceful creatures continue to thrive in both rural and urban landscapes.\n""\n""A Symbol of Resilience\n""In many cultures, squirrels are symbols of resourcefulness, adaptability, and preparation. Their ability to thrive in a variety of environments while navigating challenges with agility and grace serves as a reminder of the resilience inherent in nature. Whether you encounter them in a quiet forest, a city park, or your own backyard, squirrels are creatures that never fail to amaze with their endless energy and ingenuity.\n""In the end, squirrels may be small, but they are mighty in their ability to survive and thrive in a world that is constantly changing. So next time you spot one hopping across a branch or darting across your lawn, take a moment to appreciate the remarkable acrobat at work a true marvel of the natural world.\n") }, { .title = CLAY_STRING("Lorem Ipsum"), .contents = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") }, diff --git a/examples/cairo-pdf-rendering/main.c b/examples/cairo-pdf-rendering/main.c index 244161c..f10f990 100644 --- a/examples/cairo-pdf-rendering/main.c +++ b/examples/cairo-pdf-rendering/main.c @@ -37,11 +37,11 @@ void Layout() { static Clay_Color BACKGROUND = { 0xF4, 0xEB, 0xE6, 255 }; static Clay_Color ACCENT = { 0xFA, 0xE0, 0xD4, 255 }; - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = BACKGROUND })) { CLAY(CLAY_ID("PageMargins"), - CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, + CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .padding = { 70., 50. }, // Some nice looking page margins .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 10})) { @@ -57,8 +57,8 @@ void Layout() { )); // Feature Box - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT() }, .childGap = 10 })) { - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT() }}), CLAY_RECTANGLE({ + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(0) }, .childGap = 10 })) { + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(0) }}), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(12), })) { @@ -76,7 +76,7 @@ void Layout() { } } CLAY(CLAY_LAYOUT({ - .sizing = {CLAY_SIZING_FIT(), CLAY_SIZING_GROW()}, + .sizing = {CLAY_SIZING_FIT(0), CLAY_SIZING_GROW(0)}, .padding = { 10, 10 }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER }, @@ -84,7 +84,7 @@ void Layout() { }), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(8) })) { // Profile picture CLAY(CLAY_LAYOUT({ - .sizing = {CLAY_SIZING_FIT(), CLAY_SIZING_GROW()}, + .sizing = {CLAY_SIZING_FIT(0), CLAY_SIZING_GROW(0)}, .padding = { 30, 0 }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER }}), CLAY_BORDER_OUTSIDE_RADIUS(2, PRIMARY, 10)) { @@ -93,9 +93,9 @@ void Layout() { } } - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(16) } })); + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(16) } })); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childGap = 10, .layoutDirection = CLAY_TOP_TO_BOTTOM })) { + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childGap = 10, .layoutDirection = CLAY_TOP_TO_BOTTOM })) { CLAY_TEXT(CLAY_STRING("Cairo"), CLAY_TEXT_CONFIG({ .fontFamily = CLAY_STRING("Calistoga"), .fontSize = 24, .textColor = PRIMARY })); CLAY(CLAY_LAYOUT({ .padding = { 10, 10 } }), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(10) })) { CLAY_TEXT(CLAY_STRING("Officiis quia quia qui inventore ratione voluptas et. Quidem sunt unde similique. Qui est et exercitationem cumque harum illum. Numquam placeat aliquid quo voluptatem. " diff --git a/examples/clay-official-website/build/clay/index.wasm b/examples/clay-official-website/build/clay/index.wasm index b22f64d..c418bdb 100755 Binary files a/examples/clay-official-website/build/clay/index.wasm and b/examples/clay-official-website/build/clay/index.wasm differ diff --git a/examples/clay-official-website/main.c b/examples/clay-official-website/main.c index 21557e9..c12f9d5 100644 --- a/examples/clay-official-website/main.c +++ b/examples/clay-official-website/main.c @@ -41,18 +41,18 @@ Clay_TextElementConfig headerTextConfig = (Clay_TextElementConfig) { .fontId = 2 Clay_TextElementConfig blobTextConfig = (Clay_TextElementConfig) { .fontId = 2, .fontSize = 30, .textColor = {244, 235, 230, 255} }; void LandingPageBlob(int index, int fontSize, Clay_Color color, Clay_String text, Clay_String imageURL) { - CLAY(CLAY_IDI("HeroBlob", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 480 }) }, .padding = {16, 16}, .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_BORDER_OUTSIDE_RADIUS(2, color, 10)) { + CLAY(CLAY_IDI("HeroBlob", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 480) }, .padding = {16, 16}, .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_BORDER_OUTSIDE_RADIUS(2, color, 10)) { CLAY(CLAY_IDI("CheckImage", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(32) } }), CLAY_IMAGE({ .sourceDimensions = { 128, 128 }, .sourceURL = imageURL })) {} CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = fontSize, .fontId = FONT_ID_BODY_24, .textColor = color })); } } void LandingPageDesktop() { - CLAY(CLAY_ID("LandingPage1Desktop"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT({ .min = windowHeight - 70 }) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { .x = 50 } })) { - CLAY(CLAY_ID("LandingPage1"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { + CLAY(CLAY_ID("LandingPage1Desktop"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(.min = windowHeight - 70) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { .x = 50 } })) { + CLAY(CLAY_ID("LandingPage1"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_PERCENT(0.55f) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance."), CLAY_TEXT_CONFIG({ .fontSize = 56, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {} + CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {} CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE })); } CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_PERCENT(0.45f) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) { @@ -67,13 +67,13 @@ void LandingPageDesktop() { } void LandingPageMobile() { - CLAY(CLAY_ID("LandingPage1Mobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT({ .min = windowHeight - 70 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = { 16, 32 }, .childGap = 32 })) { - CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { + CLAY(CLAY_ID("LandingPage1Mobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(.min = windowHeight - 70) }, .childAlignment = {CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = { 16, 32 }, .childGap = 32 })) { + CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance."), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {} + CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {} CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE })); } - CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) { + CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) { LandingPageBlob(1, 28, COLOR_BLOB_BORDER_5, CLAY_STRING("High performance"), CLAY_STRING("/clay/images/check_5.png")); LandingPageBlob(2, 28, COLOR_BLOB_BORDER_4, CLAY_STRING("Flexbox-style responsive layout"), CLAY_STRING("/clay/images/check_4.png")); LandingPageBlob(3, 28, COLOR_BLOB_BORDER_3, CLAY_STRING("Declarative syntax"), CLAY_STRING("/clay/images/check_3.png")); @@ -84,8 +84,8 @@ void LandingPageMobile() { } void FeatureBlocksDesktop() { - CLAY(CLAY_ID("FeatureBlocksOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() } })) { - CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) { + CLAY(CLAY_ID("FeatureBlocksOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) } })) { + CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) { Clay_TextElementConfig *textConfig = CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_RED }); CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_PERCENT(0.5f) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {50, 32}, .childGap = 8 })) { CLAY(CLAY_ID("HFileIncludeOuter"), CLAY_LAYOUT({ .padding = {8, 4} }), CLAY_RECTANGLE({ .color = COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(8) })) { @@ -104,16 +104,16 @@ void FeatureBlocksDesktop() { } void FeatureBlocksMobile() { - CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) { + CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) { Clay_TextElementConfig *textConfig = CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_RED }); - CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 8 })) { + CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 8 })) { CLAY(CLAY_ID("HFileIncludeOuter"), CLAY_LAYOUT({ .padding = {8, 4} }), CLAY_RECTANGLE({ .color = COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(8) })) { CLAY_TEXT(CLAY_STRING("#include clay.h"), CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_LIGHT })); } CLAY_TEXT(CLAY_STRING("~2000 lines of C99."), textConfig); CLAY_TEXT(CLAY_STRING("Zero dependencies, including no C standard library."), textConfig); } - CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, .y = 32}, .childGap = 8 })) { + CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, .y = 32}, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Renderer agnostic."), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = COLOR_ORANGE })); CLAY_TEXT(CLAY_STRING("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML."), textConfig); CLAY_TEXT(CLAY_STRING("Flexible output for easy compositing in your custom engine or environment."), textConfig); @@ -122,33 +122,33 @@ void FeatureBlocksMobile() { } void DeclarativeSyntaxPageDesktop() { - CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) { - CLAY(CLAY_ID("SyntaxPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { + CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) { + CLAY(CLAY_ID("SyntaxPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Declarative Syntax"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) } })) {} + CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) } })) {} CLAY_TEXT(CLAY_STRING("Flexible and readable declarative syntax with nested UI element hierarchies."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Mix elements with standard C code like loops, conditionals and functions."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); } CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) { - CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 568 }) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") })) {} + CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 568) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") })) {} } } } } void DeclarativeSyntaxPageMobile() { - CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 16 })) { - CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { + CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 16 })) { + CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Declarative Syntax"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) } })) {} + CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) } })) {} CLAY_TEXT(CLAY_STRING("Flexible and readable declarative syntax with nested UI element hierarchies."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Mix elements with standard C code like loops, conditionals and functions."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); } - CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) { - CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 568 }) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") } )) {} + CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) { + CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 568) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") } )) {} } } } @@ -165,20 +165,20 @@ Clay_Color ColorLerp(Clay_Color a, Clay_Color b, float amount) { Clay_String LOREM_IPSUM_TEXT = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."); void HighPerformancePageDesktop(float lerpValue) { - CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { + CLAY(CLAY_ID("PerformanceDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT })); - CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {} + CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {} CLAY_TEXT(CLAY_STRING("Fast enough to recompute your entire UI every frame."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); CLAY_TEXT(CLAY_STRING("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); 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_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(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), 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(0) }, .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 })); } - CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {32, 32} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) { + CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {32, 32} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) { CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT })); } } @@ -187,20 +187,20 @@ void HighPerformancePageDesktop(float lerpValue) { } void HighPerformancePageMobile(float lerpValue) { - CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { - CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { + CLAY(CLAY_ID("PerformanceMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { + CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT })); - CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {} + CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {} CLAY_TEXT(CLAY_STRING("Fast enough to recompute your entire UI every frame."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); CLAY_TEXT(CLAY_STRING("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); 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_GROW() }, .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_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.35f + 0.3f * lerpValue), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue) })) { + CLAY(CLAY_ID("PerformanceRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) { + CLAY(CLAY_ID(""), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(400) } }), CLAY_BORDER_ALL({ .width = 2, .color = COLOR_LIGHT })) { + CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.35f + 0.3f * lerpValue), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), 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 })); } - CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) { + CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) { CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT })); } } @@ -235,18 +235,18 @@ void RendererButtonInactive(Clay_String text, size_t rendererIndex) { } void RendererPageDesktop() { - CLAY(CLAY_ID("RendererPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) { - CLAY(CLAY_ID("RendererPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { + CLAY(CLAY_ID("RendererPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) { + CLAY(CLAY_ID("RendererPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) { CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Renderer & Platform Agnostic"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {} + CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {} CLAY_TEXT(CLAY_STRING("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("There's even an HTML renderer - you're looking at it right now!"), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); } CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .childAlignment = {CLAY_ALIGN_X_CENTER}, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) { CLAY_TEXT(CLAY_STRING("Try changing renderer!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_BODY_36, .textColor = COLOR_ORANGE })); - CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 32 }) } })) {} + 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"), 1); @@ -260,17 +260,17 @@ void RendererPageDesktop() { } void RendererPageMobile() { - CLAY(CLAY_ID("RendererMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) { - CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { + CLAY(CLAY_ID("RendererMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) { + CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Renderer & Platform Agnostic"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED })); - CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {} + CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {} CLAY_TEXT(CLAY_STRING("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); CLAY_TEXT(CLAY_STRING("There's even an HTML renderer - you're looking at it right now!"), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED })); } - CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) { + CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) { CLAY_TEXT(CLAY_STRING("Try changing renderer!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_BODY_36, .textColor = COLOR_ORANGE })); - CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 32}) }})) {} + 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"), 1); @@ -283,17 +283,17 @@ void RendererPageMobile() { } void DebuggerPageDesktop() { - CLAY(CLAY_ID("DebuggerDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { + CLAY(CLAY_ID("DebuggerDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) { CLAY(CLAY_ID("DebuggerLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) { CLAY_TEXT(CLAY_STRING("Integrated Debug Tools"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT })); - CLAY(CLAY_ID("DebuggerSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {} + CLAY(CLAY_ID("DebuggerSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {} CLAY_TEXT(CLAY_STRING("Clay includes built in \"Chrome Inspector\"-style debug tooling."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); CLAY_TEXT(CLAY_STRING("View your layout hierarchy and config in real time."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT })); - CLAY(CLAY_ID("DebuggerPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {} + CLAY(CLAY_ID("DebuggerPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {} CLAY_TEXT(CLAY_STRING("Press the \"d\" key to try it out now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE })); } CLAY(CLAY_ID("DebuggerRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) { - CLAY(CLAY_ID("DebuggerPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 558 }) } }), CLAY_IMAGE({ .sourceDimensions = {1620, 1474}, .sourceURL = CLAY_STRING("/clay/images/debugger.png") })) {} + CLAY(CLAY_ID("DebuggerPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 558) } }), CLAY_IMAGE({ .sourceDimensions = {1620, 1474}, .sourceURL = CLAY_STRING("/clay/images/debugger.png") })) {} } } } @@ -310,10 +310,10 @@ 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 = 16, .padding = { 32 } })) { + CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) } }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) { + CLAY(CLAY_ID("Header"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), 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() } })) {} + CLAY(CLAY_ID("Spacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) } })) {} if (!mobileScreen) { 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} })); @@ -338,14 +338,14 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) { CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} })); } } - Clay_LayoutConfig topBorderConfig = (Clay_LayoutConfig) { .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(4) }}; + Clay_LayoutConfig topBorderConfig = (Clay_LayoutConfig) { .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(4) }}; CLAY(CLAY_ID("TopBorder1"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_5 })) {} CLAY(CLAY_ID("TopBorder2"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_4 })) {} CLAY(CLAY_ID("TopBorder3"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_3 })) {} CLAY(CLAY_ID("TopBorder4"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_2 })) {} CLAY(CLAY_ID("TopBorder5"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_1 })) {} CLAY(CLAY_ID("OuterScrollContainer"), - CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM }), + CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_SCROLL({ .vertical = true }), CLAY_BORDER({ .betweenChildren = {2, COLOR_RED} }) ) { @@ -457,4 +457,4 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa // Dummy main() to please cmake - TODO get wasm working with cmake on this example int main() { return 0; -} \ No newline at end of file +} diff --git a/examples/cpp-project-example/CMakeLists.txt b/examples/cpp-project-example/CMakeLists.txt index 7e00ae5..24422d7 100644 --- a/examples/cpp-project-example/CMakeLists.txt +++ b/examples/cpp-project-example/CMakeLists.txt @@ -2,11 +2,15 @@ cmake_minimum_required(VERSION 3.27) project(clay_examples_cpp_project_example CXX) set(CMAKE_CXX_STANDARD 20) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g") +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g") +endif() add_executable(clay_examples_cpp_project_example main.cpp) target_include_directories(clay_examples_cpp_project_example PUBLIC .) -set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall") -set(CMAKE_CXX_FLAGS_RELEASE "-O3") +if(NOT MSVC) + set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall") + set(CMAKE_CXX_FLAGS_RELEASE "-O3") +endif() diff --git a/examples/introducing-clay-video-demo/CMakeLists.txt b/examples/introducing-clay-video-demo/CMakeLists.txt index 859165e..a59d678 100644 --- a/examples/introducing-clay-video-demo/CMakeLists.txt +++ b/examples/introducing-clay-video-demo/CMakeLists.txt @@ -25,8 +25,12 @@ target_include_directories(clay_examples_introducing_clay_video_demo PUBLIC .) target_link_libraries(clay_examples_introducing_clay_video_demo PUBLIC raylib) -set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") -set(CMAKE_C_FLAGS_RELEASE "-O3") +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG") +else() + set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") + set(CMAKE_C_FLAGS_RELEASE "-O3") +endif() add_custom_command( TARGET clay_examples_introducing_clay_video_demo POST_BUILD diff --git a/examples/introducing-clay-video-demo/main.c b/examples/introducing-clay-video-demo/main.c index 88a0c15..8f3ae42 100644 --- a/examples/introducing-clay-video-demo/main.c +++ b/examples/introducing-clay-video-demo/main.c @@ -111,8 +111,8 @@ int main(void) { ); Clay_Sizing layoutExpand = { - .width = CLAY_SIZING_GROW(), - .height = CLAY_SIZING_GROW() + .width = CLAY_SIZING_GROW(0), + .height = CLAY_SIZING_GROW(0) }; Clay_RectangleElementConfig contentBackgroundConfig = { @@ -139,7 +139,7 @@ int main(void) { CLAY_LAYOUT({ .sizing = { .height = CLAY_SIZING_FIXED(60), - .width = CLAY_SIZING_GROW() + .width = CLAY_SIZING_GROW(0) }, .padding = { 16 }, .childGap = 16, @@ -201,7 +201,7 @@ int main(void) { } } RenderHeaderButton(CLAY_STRING("Edit")); - CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {} + CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }})) {} RenderHeaderButton(CLAY_STRING("Upload")); RenderHeaderButton(CLAY_STRING("Media")); RenderHeaderButton(CLAY_STRING("Support")); @@ -220,14 +220,14 @@ int main(void) { .childGap = 8, .sizing = { .width = CLAY_SIZING_FIXED(250), - .height = CLAY_SIZING_GROW() + .height = CLAY_SIZING_GROW(0) } }) ) { for (int i = 0; i < documents.length; i++) { Document document = documents.documents[i]; Clay_LayoutConfig sidebarButtonLayout = { - .sizing = { .width = CLAY_SIZING_GROW() }, + .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = { 16, 16 } }; diff --git a/examples/raylib-multi-context/CMakeLists.txt b/examples/raylib-multi-context/CMakeLists.txt new file mode 100644 index 0000000..d5611cd --- /dev/null +++ b/examples/raylib-multi-context/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.27) +project(clay_examples_raylib_multi_context C) +set(CMAKE_C_STANDARD 99) + +# Adding Raylib +include(FetchContent) +set(FETCHCONTENT_QUIET FALSE) +set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples +set(BUILD_GAMES OFF CACHE BOOL "" FORCE) # don't build the supplied example games + +FetchContent_Declare( + raylib + GIT_REPOSITORY "https://github.com/raysan5/raylib.git" + GIT_TAG "master" + GIT_PROGRESS TRUE + GIT_SHALLOW TRUE +) + +FetchContent_MakeAvailable(raylib) + +add_executable(clay_examples_raylib_multi_context main.c) + +target_compile_options(clay_examples_raylib_multi_context PUBLIC) +target_include_directories(clay_examples_raylib_multi_context PUBLIC .) + +target_link_libraries(clay_examples_raylib_multi_context PUBLIC raylib) + +set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") +set(CMAKE_C_FLAGS_RELEASE "-O3") + +add_custom_command( + TARGET clay_examples_raylib_multi_context POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_CURRENT_SOURCE_DIR}/resources + ${CMAKE_CURRENT_BINARY_DIR}/resources) diff --git a/examples/raylib-multi-context/main.c b/examples/raylib-multi-context/main.c new file mode 100644 index 0000000..6ce7c1b --- /dev/null +++ b/examples/raylib-multi-context/main.c @@ -0,0 +1,267 @@ +#define CLAY_IMPLEMENTATION +#include "../../clay.h" +#include "../../renderers/raylib/clay_renderer_raylib.c" + +const int FONT_ID_BODY_16 = 0; +Clay_Color COLOR_WHITE = { 255, 255, 255, 255}; + +void RenderHeaderButton(Clay_String text) { + CLAY( + CLAY_LAYOUT({ .padding = { 16, 8 }}), + CLAY_RECTANGLE({ + .color = { 140, 140, 140, 255 }, + .cornerRadius = 5 + }) + ) { + CLAY_TEXT(text, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 16, + .textColor = { 255, 255, 255, 255 } + })); + } +} + +void RenderDropdownMenuItem(Clay_String text) { + CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) { + CLAY_TEXT(text, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 16, + .textColor = { 255, 255, 255, 255 } + })); + } +} + +typedef struct { + Clay_String title; + Clay_String contents; +} Document; + +typedef struct { + Document *documents; + int32_t length; +} DocumentArray; + +DocumentArray documents = { + .documents = NULL, // TODO figure out if it's possible to const init this list + .length = 5 +}; + +int32_t selectedDocumentIndexTop = 0; +int32_t selectedDocumentIndexBottom = 0; + +typedef struct { + int32_t requestedDocumentIndex; + int32_t* selectedDocumentIndex; +} SidebarClickData; + +void HandleSidebarInteraction( + Clay_ElementId elementId, + Clay_PointerData pointerData, + intptr_t userData +) { + SidebarClickData *clickData = (SidebarClickData*)userData; + // If this button was clicked + if (pointerData.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { + if (clickData->requestedDocumentIndex >= 0 && clickData->requestedDocumentIndex < documents.length) { + // Select the corresponding document + *clickData->selectedDocumentIndex = clickData->requestedDocumentIndex; + } + } +} + +// This function is new since the video was published +void HandleClayErrors(Clay_ErrorData errorData) { + printf("%s", errorData.errorText.chars); +} + +typedef struct { + intptr_t next; + intptr_t memory; +} Arena; + +Arena frameArena = {}; + +Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32_t* documentIndex) { + Clay_SetCurrentContext(context); + Clay_SetDebugModeEnabled(true); + // Run once per frame + Clay_SetLayoutDimensions((Clay_Dimensions) { + .width = GetScreenWidth(), + .height = GetScreenHeight() / 2 + }); + + Vector2 mousePosition = GetMousePosition(); + mousePosition.y -= yOffset; + Vector2 scrollDelta = GetMouseWheelMoveV(); + Clay_SetPointerState( + (Clay_Vector2) { mousePosition.x, mousePosition.y }, + IsMouseButtonDown(0) + ); + Clay_UpdateScrollContainers( + true, + (Clay_Vector2) { scrollDelta.x, scrollDelta.y }, + GetFrameTime() + ); + + Clay_Sizing layoutExpand = { + .width = CLAY_SIZING_GROW(), + .height = CLAY_SIZING_GROW() + }; + + Clay_RectangleElementConfig contentBackgroundConfig = { + .color = { 90, 90, 90, 255 }, + .cornerRadius = 8 + }; + + Clay_BeginLayout(); + // Build UI here + CLAY( + CLAY_ID("OuterContainer"), + CLAY_RECTANGLE({ .color = { 43, 41, 51, 255 } }), + CLAY_LAYOUT({ + .layoutDirection = CLAY_TOP_TO_BOTTOM, + .sizing = layoutExpand, + .padding = { 16, 16 }, + .childGap = 16 + }) + ) { + CLAY( + CLAY_ID("LowerContent"), + CLAY_LAYOUT({ .sizing = layoutExpand, .childGap = 16 }) + ) { + CLAY( + CLAY_ID("Sidebar"), + CLAY_RECTANGLE(contentBackgroundConfig), + CLAY_LAYOUT({ + .layoutDirection = CLAY_TOP_TO_BOTTOM, + .padding = { 16, 16 }, + .childGap = 8, + .sizing = { + .width = CLAY_SIZING_FIXED(250), + .height = CLAY_SIZING_GROW() + } + }) + ) { + for (int i = 0; i < documents.length; i++) { + Document document = documents.documents[i]; + Clay_LayoutConfig sidebarButtonLayout = { + .sizing = { .width = CLAY_SIZING_GROW() }, + .padding = { 16, 16 } + }; + + if (i == *documentIndex) { + CLAY( + CLAY_LAYOUT(sidebarButtonLayout), + CLAY_RECTANGLE({ + .color = { 120, 120, 120, 255 }, + .cornerRadius = 8, + }) + ) { + CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 20, + .textColor = { 255, 255, 255, 255 } + })); + } + } else { + SidebarClickData *clickData = (SidebarClickData *)frameArena.next; + *clickData = (SidebarClickData) { .requestedDocumentIndex = i, .selectedDocumentIndex = documentIndex }; + frameArena.next += sizeof(SidebarClickData); + CLAY( + CLAY_LAYOUT(sidebarButtonLayout), + Clay_OnHover(HandleSidebarInteraction, (intptr_t)clickData), + Clay_Hovered() + ? CLAY_RECTANGLE({ + .color = { 120, 120, 120, 120 }, + .cornerRadius = 8 + }) + : 0 + ) { + CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 20, + .textColor = { 255, 255, 255, 255 } + })); + } + } + } + } + + CLAY( + CLAY_ID("MainContent"), + CLAY_RECTANGLE(contentBackgroundConfig), + CLAY_SCROLL({ .vertical = true }), + CLAY_LAYOUT({ + .layoutDirection = CLAY_TOP_TO_BOTTOM, + .childGap = 16, + .padding = { 16, 16 }, + .sizing = layoutExpand + }) + ) { + Document selectedDocument = documents.documents[*documentIndex]; + CLAY_TEXT(selectedDocument.title, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 24, + .textColor = COLOR_WHITE + })); + CLAY_TEXT(selectedDocument.contents, CLAY_TEXT_CONFIG({ + .fontId = FONT_ID_BODY_16, + .fontSize = 24, + .textColor = COLOR_WHITE + })); + } + } + } + + Clay_RenderCommandArray renderCommands = Clay_EndLayout(); + for (int i = 0; i < renderCommands.length; ++i) { + Clay_RenderCommandArray_Get(&renderCommands,i)->boundingBox.y += yOffset; + } + return renderCommands; +} + + +int main(void) { + frameArena = (Arena) { .memory = (intptr_t)malloc(1024) }; + frameArena.next = frameArena.memory; + documents.documents = (Document[]) { + { .title = CLAY_STRING("Squirrels"), .contents = CLAY_STRING("The Secret Life of Squirrels: Nature's Clever Acrobats\n""Squirrels are often overlooked creatures, dismissed as mere park inhabitants or backyard nuisances. Yet, beneath their fluffy tails and twitching noses lies an intricate world of cunning, agility, and survival tactics that are nothing short of fascinating. As one of the most common mammals in North America, squirrels have adapted to a wide range of environments from bustling urban centers to tranquil forests and have developed a variety of unique behaviors that continue to intrigue scientists and nature enthusiasts alike.\n""\n""Master Tree Climbers\n""At the heart of a squirrel's skill set is its impressive ability to navigate trees with ease. Whether they're darting from branch to branch or leaping across wide gaps, squirrels possess an innate talent for acrobatics. Their powerful hind legs, which are longer than their front legs, give them remarkable jumping power. With a tail that acts as a counterbalance, squirrels can leap distances of up to ten times the length of their body, making them some of the best aerial acrobats in the animal kingdom.\n""But it's not just their agility that makes them exceptional climbers. Squirrels' sharp, curved claws allow them to grip tree bark with precision, while the soft pads on their feet provide traction on slippery surfaces. Their ability to run at high speeds and scale vertical trunks with ease is a testament to the evolutionary adaptations that have made them so successful in their arboreal habitats.\n""\n""Food Hoarders Extraordinaire\n""Squirrels are often seen frantically gathering nuts, seeds, and even fungi in preparation for winter. While this behavior may seem like instinctual hoarding, it is actually a survival strategy that has been honed over millions of years. Known as \"scatter hoarding,\" squirrels store their food in a variety of hidden locations, often burying it deep in the soil or stashing it in hollowed-out tree trunks.\n""Interestingly, squirrels have an incredible memory for the locations of their caches. Research has shown that they can remember thousands of hiding spots, often returning to them months later when food is scarce. However, they don't always recover every stash some forgotten caches eventually sprout into new trees, contributing to forest regeneration. This unintentional role as forest gardeners highlights the ecological importance of squirrels in their ecosystems.\n""\n""The Great Squirrel Debate: Urban vs. Wild\n""While squirrels are most commonly associated with rural or wooded areas, their adaptability has allowed them to thrive in urban environments as well. In cities, squirrels have become adept at finding food sources in places like parks, streets, and even garbage cans. However, their urban counterparts face unique challenges, including traffic, predators, and the lack of natural shelters. Despite these obstacles, squirrels in urban areas are often observed using human infrastructure such as buildings, bridges, and power lines as highways for their acrobatic escapades.\n""There is, however, a growing concern regarding the impact of urban life on squirrel populations. Pollution, deforestation, and the loss of natural habitats are making it more difficult for squirrels to find adequate food and shelter. As a result, conservationists are focusing on creating squirrel-friendly spaces within cities, with the goal of ensuring these resourceful creatures continue to thrive in both rural and urban landscapes.\n""\n""A Symbol of Resilience\n""In many cultures, squirrels are symbols of resourcefulness, adaptability, and preparation. Their ability to thrive in a variety of environments while navigating challenges with agility and grace serves as a reminder of the resilience inherent in nature. Whether you encounter them in a quiet forest, a city park, or your own backyard, squirrels are creatures that never fail to amaze with their endless energy and ingenuity.\n""In the end, squirrels may be small, but they are mighty in their ability to survive and thrive in a world that is constantly changing. So next time you spot one hopping across a branch or darting across your lawn, take a moment to appreciate the remarkable acrobat at work a true marvel of the natural world.\n") }, + { .title = CLAY_STRING("Lorem Ipsum"), .contents = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") }, + { .title = CLAY_STRING("Vacuum Instructions"), .contents = CLAY_STRING("Chapter 3: Getting Started - Unpacking and Setup\n""\n""Congratulations on your new SuperClean Pro 5000 vacuum cleaner! In this section, we will guide you through the simple steps to get your vacuum up and running. Before you begin, please ensure that you have all the components listed in the \"Package Contents\" section on page 2.\n""\n""1. Unboxing Your Vacuum\n""Carefully remove the vacuum cleaner from the box. Avoid using sharp objects that could damage the product. Once removed, place the unit on a flat, stable surface to proceed with the setup. Inside the box, you should find:\n""\n"" The main vacuum unit\n"" A telescoping extension wand\n"" A set of specialized cleaning tools (crevice tool, upholstery brush, etc.)\n"" A reusable dust bag (if applicable)\n"" A power cord with a 3-prong plug\n"" A set of quick-start instructions\n""\n""2. Assembling Your Vacuum\n""Begin by attaching the extension wand to the main body of the vacuum cleaner. Line up the connectors and twist the wand into place until you hear a click. Next, select the desired cleaning tool and firmly attach it to the wand's end, ensuring it is securely locked in.\n""\n""For models that require a dust bag, slide the bag into the compartment at the back of the vacuum, making sure it is properly aligned with the internal mechanism. If your vacuum uses a bagless system, ensure the dust container is correctly seated and locked in place before use.\n""\n""3. Powering On\n""To start the vacuum, plug the power cord into a grounded electrical outlet. Once plugged in, locate the power switch, usually positioned on the side of the handle or body of the unit, depending on your model. Press the switch to the \"On\" position, and you should hear the motor begin to hum. If the vacuum does not power on, check that the power cord is securely plugged in, and ensure there are no blockages in the power switch.\n""\n""Note: Before first use, ensure that the vacuum filter (if your model has one) is properly installed. If unsure, refer to \"Section 5: Maintenance\" for filter installation instructions.") }, + { .title = CLAY_STRING("Article 4"), .contents = CLAY_STRING("Article 4") }, + { .title = CLAY_STRING("Article 5"), .contents = CLAY_STRING("Article 5") }, + }; + Clay_Raylib_Initialize(1024, 768, "Introducing Clay Demo", FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT | FLAG_VSYNC_HINT); // Extra parameters to this function are new since the video was published + + uint64_t clayRequiredMemory = Clay_MinMemorySize(); + + Clay_Arena clayMemoryTop = Clay_CreateArenaWithCapacityAndMemory(clayRequiredMemory, malloc(clayRequiredMemory)); + Clay_Context *clayContextTop = Clay_Initialize(clayMemoryTop, (Clay_Dimensions) { + .width = GetScreenWidth(), + .height = GetScreenHeight() / 2 + }, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published + + Clay_Arena clayMemoryBottom = Clay_CreateArenaWithCapacityAndMemory(clayRequiredMemory, malloc(clayRequiredMemory)); + Clay_Context *clayContextBottom = Clay_Initialize(clayMemoryBottom, (Clay_Dimensions) { + .width = GetScreenWidth(), + .height = GetScreenHeight() / 2 + }, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published + + Clay_SetMeasureTextFunction(Raylib_MeasureText); + Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) { + .font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400), + .fontId = FONT_ID_BODY_16 + }; + SetTextureFilter(Raylib_fonts[FONT_ID_BODY_16].font.texture, TEXTURE_FILTER_BILINEAR); + + while (!WindowShouldClose()) { + frameArena.next = frameArena.memory; + Clay_RenderCommandArray renderCommandsTop = CreateLayout(clayContextTop, 0, &selectedDocumentIndexTop); + Clay_RenderCommandArray renderCommandsBottom = CreateLayout(clayContextBottom, GetScreenHeight() / 2, &selectedDocumentIndexBottom); + BeginDrawing(); + ClearBackground(BLACK); + Clay_Raylib_Render(renderCommandsTop); + Clay_Raylib_Render(renderCommandsBottom); + EndDrawing(); + } +} diff --git a/examples/raylib-multi-context/resources/Roboto-Regular.ttf b/examples/raylib-multi-context/resources/Roboto-Regular.ttf new file mode 100644 index 0000000..ddf4bfa Binary files /dev/null and b/examples/raylib-multi-context/resources/Roboto-Regular.ttf differ diff --git a/examples/raylib-multi-context/resources/RobotoMono-Medium.ttf b/examples/raylib-multi-context/resources/RobotoMono-Medium.ttf new file mode 100644 index 0000000..f6c149a Binary files /dev/null and b/examples/raylib-multi-context/resources/RobotoMono-Medium.ttf differ diff --git a/examples/raylib-multi-context/resources/profile-picture.png b/examples/raylib-multi-context/resources/profile-picture.png new file mode 100644 index 0000000..8c4ea3e Binary files /dev/null and b/examples/raylib-multi-context/resources/profile-picture.png differ diff --git a/examples/raylib-sidebar-scrolling-container/CMakeLists.txt b/examples/raylib-sidebar-scrolling-container/CMakeLists.txt index 2aad78b..8f746ed 100644 --- a/examples/raylib-sidebar-scrolling-container/CMakeLists.txt +++ b/examples/raylib-sidebar-scrolling-container/CMakeLists.txt @@ -25,8 +25,12 @@ target_include_directories(clay_examples_raylib_sidebar_scrolling_container PUBL target_link_libraries(clay_examples_raylib_sidebar_scrolling_container PUBLIC raylib) -set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") -set(CMAKE_C_FLAGS_RELEASE "-O3") +if(MSVC) + set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG") +else() + set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG") + set(CMAKE_C_FLAGS_RELEASE "-O3") +endif() add_custom_command( TARGET clay_examples_raylib_sidebar_scrolling_container POST_BUILD diff --git a/examples/raylib-sidebar-scrolling-container/main.c b/examples/raylib-sidebar-scrolling-container/main.c index 5a39fc1..3f5f6e3 100644 --- a/examples/raylib-sidebar-scrolling-container/main.c +++ b/examples/raylib-sidebar-scrolling-container/main.c @@ -10,8 +10,8 @@ const uint32_t FONT_ID_BODY_16 = 1; Texture2D profilePicture; #define RAYLIB_VECTOR2_TO_CLAY_VECTOR2(vector) (Clay_Vector2) { .x = vector.x, .y = vector.y } -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} }; +Clay_String profileText = CLAY_STRING_CONST("Profile Page one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen"); +Clay_TextElementConfig headerTextConfig = { .fontId = 1, .fontSize = 16, .textColor = {0,0,0,255} }; void HandleHeaderButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData) { if (pointerData.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) { @@ -28,9 +28,9 @@ void RenderHeaderButton(Clay_String text) { } } -Clay_LayoutConfig dropdownTextItemLayout = (Clay_LayoutConfig) { .padding = {8, 4} }; -Clay_RectangleElementConfig dropdownRectangleConfig = (Clay_RectangleElementConfig) { .color = {180, 180, 180, 255} }; -Clay_TextElementConfig dropdownTextElementConfig = (Clay_TextElementConfig) { .fontSize = 24, .textColor = {255,255,255,255} }; +Clay_LayoutConfig dropdownTextItemLayout = { .padding = {8, 4} }; +Clay_RectangleElementConfig dropdownRectangleConfig = { .color = {180, 180, 180, 255} }; +Clay_TextElementConfig dropdownTextElementConfig = { .fontSize = 24, .textColor = {255,255,255,255} }; void RenderDropdownTextItem(int index) { CLAY(CLAY_IDI("ScrollContainerItem", index), CLAY_LAYOUT(dropdownTextItemLayout), CLAY_RECTANGLE(dropdownRectangleConfig)) { @@ -40,27 +40,27 @@ void RenderDropdownTextItem(int index) { Clay_RenderCommandArray CreateLayout() { Clay_BeginLayout(); - 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} })) { + CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }, .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(0) }, .padding = {16, 16}, .childGap = 16 }), CLAY_RECTANGLE({ .color = {150, 150, 255, 255} })) { + CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = { 8, 8 }, .childGap = 8, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_RECTANGLE({ .color = {130, 130, 255, 255} })) { CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) } }), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {} CLAY_TEXT(profileText, CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {0, 0, 0, 255} })); } - CLAY(CLAY_ID("SidebarBlob1"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} - CLAY(CLAY_ID("SidebarBlob2"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} - CLAY(CLAY_ID("SidebarBlob3"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} - CLAY(CLAY_ID("SidebarBlob4"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} + CLAY(CLAY_ID("SidebarBlob1"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} + CLAY(CLAY_ID("SidebarBlob2"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} + CLAY(CLAY_ID("SidebarBlob3"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} + CLAY(CLAY_ID("SidebarBlob4"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }}), CLAY_RECTANGLE({ .color = {110, 110, 255, 255} })) {} } - 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} })) { + CLAY(CLAY_ID("RightPanel"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }, .childGap = 16 })) { + CLAY(CLAY_ID("HeaderBar"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT }, .padding = {8, 8}, .childGap = 8 }), CLAY_RECTANGLE({ .color = {180, 180, 180, 255} })) { 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 }), - CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .padding = {16, 16}, .childGap = 16, .sizing = { CLAY_SIZING_GROW() } }), + CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .padding = {16, 16}, .childGap = 16, .sizing = { CLAY_SIZING_GROW(0) } }), CLAY_RECTANGLE({ .color = {200, 200, 255, 255} })) { CLAY(CLAY_ID("FloatingContainer"), @@ -87,7 +87,7 @@ Clay_RenderCommandArray CreateLayout() { CLAY_TEXT(CLAY_STRING("Suspendisse in est ante in nibh. Amet venenatis urna cursus eget nunc scelerisque viverra. Elementum sagittis vitae et leo duis ut diam quam nulla. Enim nulla aliquet porttitor lacus. Pellentesque habitant morbi tristique senectus et. Facilisi nullam vehicula ipsum a arcu cursus vitae.\nSem fringilla ut morbi tincidunt. Euismod quis viverra nibh cras pulvinar mattis nunc sed. Velit sed ullamcorper morbi tincidunt ornare massa. Varius quam quisque id diam vel quam. Nulla pellentesque dignissim enim sit amet venenatis. Enim lobortis scelerisque fermentum dui faucibus in. Pretium viverra suspendisse potenti nullam ac tortor vitae. Lectus vestibulum mattis ullamcorper velit sed. Eget mauris pharetra et ultrices neque ornare aenean euismod elementum. Habitant morbi tristique senectus et. Integer vitae justo eget magna fermentum iaculis eu. Semper quis lectus nulla at volutpat diam. Enim praesent elementum facilisis leo. Massa vitae tortor condimentum lacinia quis vel."), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {0,0,0,255} })); - CLAY(CLAY_ID("Photos"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childGap = 16, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = {180, 180, 220, 255} })) { + CLAY(CLAY_ID("Photos"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER }, .childGap = 16, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = {180, 180, 220, 255} })) { CLAY(CLAY_ID("Picture2"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(120), .height = CLAY_SIZING_FIXED(120) }}), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {120, 120} })) {} CLAY(CLAY_ID("Picture1"), CLAY_LAYOUT({ .childAlignment = { .x = CLAY_ALIGN_X_CENTER }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .padding = {8, 8} }), CLAY_RECTANGLE({ .color = {170, 170, 220, 255} })) { CLAY(CLAY_ID("ProfilePicture2"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {} @@ -142,7 +142,7 @@ typedef struct bool mouseDown; } ScrollbarData; -ScrollbarData scrollbarData = (ScrollbarData) {}; +ScrollbarData scrollbarData = {}; bool debugEnabled = false; @@ -208,10 +208,10 @@ void HandleClayErrors(Clay_ErrorData errorData) { printf("%s", errorData.errorText.chars); if (errorData.errorType == CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED) { reinitializeClay = true; - Clay_SetMaxElementCount(Clay__maxElementCount * 2); + Clay_SetMaxElementCount(Clay_GetMaxElementCount() * 2); } else if (errorData.errorType == CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED) { reinitializeClay = true; - Clay_SetMaxMeasureTextCacheWordCount(Clay__maxMeasureTextCacheWordCount * 2); + Clay_SetMaxMeasureTextCacheWordCount(Clay_GetMaxMeasureTextCacheWordCount() * 2); } } diff --git a/renderers/SDL2/clay_renderer_SDL2.c b/renderers/SDL2/clay_renderer_SDL2.c index 698f0a3..0a0785a 100644 --- a/renderers/SDL2/clay_renderer_SDL2.c +++ b/renderers/SDL2/clay_renderer_SDL2.c @@ -1,6 +1,7 @@ #include "../../clay.h" #include #include +#include typedef struct {