/ examples / clay.h
clay.h
   1  // VERSION: 0.14
   2  
   3  /*
   4      NOTE: In order to use this library you must define
   5      the following macro in exactly one file, _before_ including clay.h:
   6  
   7      #define CLAY_IMPLEMENTATION
   8      #include "clay.h"
   9  
  10      See the examples folder for details.
  11  */
  12  
  13  #include <stdint.h>
  14  #include <stdbool.h>
  15  #include <stddef.h>
  16  
  17  // SIMD includes on supported platforms
  18  #if !defined(CLAY_DISABLE_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64))
  19  #include <emmintrin.h>
  20  #elif !defined(CLAY_DISABLE_SIMD) && defined(__aarch64__)
  21  #include <arm_neon.h>
  22  #endif
  23  #if __CLION_IDE__
  24  #define CLAY_IMPLEMENTATION
  25  #endif
  26  
  27  // -----------------------------------------
  28  // HEADER DECLARATIONS ---------------------
  29  // -----------------------------------------
  30  
  31  #ifndef CLAY_HEADER
  32  #define CLAY_HEADER
  33  
  34  #if !( \
  35      (defined(__cplusplus) && __cplusplus >= 202002L) || \
  36      (defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
  37      defined(_MSC_VER) || \
  38      defined(__OBJC__) \
  39  )
  40  #error "Clay requires C99, C++20, or MSVC"
  41  #endif
  42  
  43  #ifdef CLAY_WASM
  44  #define CLAY_WASM_EXPORT(name) __attribute__((export_name(name)))
  45  #else
  46  #define CLAY_WASM_EXPORT(null)
  47  #endif
  48  
  49  #ifdef CLAY_DLL
  50  #define CLAY_DLL_EXPORT __declspec(dllexport) __stdcall
  51  #else
  52  #define CLAY_DLL_EXPORT
  53  #endif
  54  
  55  // Public Macro API ------------------------
  56  
  57  #define CLAY__MAX(x, y) (((x) > (y)) ? (x) : (y))
  58  #define CLAY__MIN(x, y) (((x) < (y)) ? (x) : (y))
  59  
  60  #define CLAY_TEXT_CONFIG(...) __VA_ARGS__
  61  
  62  #define CLAY_BORDER_OUTSIDE(widthValue) {widthValue, widthValue, widthValue, widthValue, 0}
  63  
  64  #define CLAY_BORDER_ALL(widthValue) {widthValue, widthValue, widthValue, widthValue, widthValue}
  65  
  66  #define CLAY_CORNER_RADIUS(radius) (CLAY__INIT(Clay_CornerRadius) { radius, radius, radius, radius })
  67  
  68  #define CLAY_PADDING_ALL(padding) CLAY__CONFIG_WRAPPER(Clay_Padding, { padding, padding, padding, padding })
  69  
  70  #define CLAY_SIZING_FIT(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { __VA_ARGS__ } }, .type = CLAY__SIZING_TYPE_FIT })
  71  
  72  #define CLAY_SIZING_GROW(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { __VA_ARGS__ } }, .type = CLAY__SIZING_TYPE_GROW })
  73  
  74  #define CLAY_SIZING_FIXED(fixedSize) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = { fixedSize, fixedSize } }, .type = CLAY__SIZING_TYPE_FIXED })
  75  
  76  #define CLAY_SIZING_PERCENT(percentOfParent) (CLAY__INIT(Clay_SizingAxis) { .size = { .percent = (percentOfParent) }, .type = CLAY__SIZING_TYPE_PERCENT })
  77  
  78  // Note: If a compile error led you here, you might be trying to use CLAY_ID with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID instead.
  79  #define CLAY_ID(label) CLAY_SID(CLAY_STRING(label))
  80  
  81  #define CLAY_SID(label) Clay__HashString(label, 0)
  82  
  83  // Note: If a compile error led you here, you might be trying to use CLAY_IDI with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI instead.
  84  #define CLAY_IDI(label, index) CLAY_SIDI(CLAY_STRING(label), index)
  85  
  86  #define CLAY_SIDI(label, index) Clay__HashStringWithOffset(label, index, 0)
  87  
  88  // Note: If a compile error led you here, you might be trying to use CLAY_ID_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID_LOCAL instead.
  89  #define CLAY_ID_LOCAL(label) CLAY_SID_LOCAL(CLAY_STRING(label))
  90  
  91  #define CLAY_SID_LOCAL(label) Clay__HashString(label, Clay_GetOpenElementId())
  92  
  93  // Note: If a compile error led you here, you might be trying to use CLAY_IDI_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI_LOCAL instead.
  94  #define CLAY_IDI_LOCAL(label, index) CLAY_SIDI_LOCAL(CLAY_STRING(label), index)
  95  
  96  #define CLAY_SIDI_LOCAL(label, index) Clay__HashStringWithOffset(label, index, Clay_GetOpenElementId())
  97  
  98  #define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0]))
  99  
 100  #define CLAY__ENSURE_STRING_LITERAL(x) ("" x "")
 101  
 102  // 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)
 103  #define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) })
 104  
 105  #define CLAY_STRING_CONST(string) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }
 106  
 107  static uint8_t CLAY__ELEMENT_DEFINITION_LATCH;
 108  
 109  // GCC marks the above CLAY__ELEMENT_DEFINITION_LATCH as an unused variable for files that include clay.h but don't declare any layout
 110  // This is to suppress that warning
 111  static inline void Clay__SuppressUnusedLatchDefinitionVariableWarning(void) { (void) CLAY__ELEMENT_DEFINITION_LATCH; }
 112  
 113  // Publicly visible layout element macros -----------------------------------------------------
 114  
 115  /* This macro looks scary on the surface, but is actually quite simple.
 116    It turns a macro call like this:
 117  
 118    CLAY({
 119      .id = CLAY_ID("Container"),
 120      .backgroundColor = { 255, 200, 200, 255 }
 121    }) {
 122        ...children declared here
 123    }
 124  
 125    Into calls like this:
 126  
 127    Clay__OpenElement();
 128    Clay__ConfigureOpenElement((Clay_ElementDeclaration) {
 129      .id = CLAY_ID("Container"),
 130      .backgroundColor = { 255, 200, 200, 255 }
 131    });
 132    ...children declared here
 133    Clay__CloseElement();
 134  
 135    The for loop will only ever run a single iteration, putting Clay__CloseElement() in the increment of the loop
 136    means that it will run after the body - where the children are declared. It just exists to make sure you don't forget
 137    to call Clay_CloseElement().
 138  */
 139  #define CLAY_AUTO_ID(...)                                                                                                                                   \
 140      for (                                                                                                                                                   \
 141          CLAY__ELEMENT_DEFINITION_LATCH = (Clay__OpenElement(), Clay__ConfigureOpenElement(CLAY__CONFIG_WRAPPER(Clay_ElementDeclaration, __VA_ARGS__)), 0);  \
 142          CLAY__ELEMENT_DEFINITION_LATCH < 1;                                                                                                                 \
 143          CLAY__ELEMENT_DEFINITION_LATCH=1, Clay__CloseElement()                                                                                              \
 144      )
 145  
 146  #define CLAY(id, ...)                                                                                                                                               \
 147      for (                                                                                                                                                           \
 148          CLAY__ELEMENT_DEFINITION_LATCH = (Clay__OpenElementWithId(id), Clay__ConfigureOpenElement(CLAY__CONFIG_WRAPPER(Clay_ElementDeclaration, __VA_ARGS__)), 0);  \
 149          CLAY__ELEMENT_DEFINITION_LATCH < 1;                                                                                                                         \
 150          CLAY__ELEMENT_DEFINITION_LATCH=1, Clay__CloseElement()                                                                                                      \
 151      )
 152  
 153  // These macros exist to allow the CLAY() macro to be called both with an inline struct definition, such as
 154  // CLAY({ .id = something... });
 155  // As well as by passing a predefined declaration struct
 156  // Clay_ElementDeclaration declarationStruct = ...
 157  // CLAY(declarationStruct);
 158  #define CLAY__WRAPPER_TYPE(type) Clay__##type##Wrapper
 159  #define CLAY__WRAPPER_STRUCT(type) typedef struct { type wrapped; } CLAY__WRAPPER_TYPE(type)
 160  #define CLAY__CONFIG_WRAPPER(type, ...) (CLAY__INIT(CLAY__WRAPPER_TYPE(type)) { __VA_ARGS__ }).wrapped
 161  
 162  #define CLAY_TEXT(text, ...) Clay__OpenTextElement(text, CLAY__CONFIG_WRAPPER(Clay_TextElementConfig, __VA_ARGS__))
 163  
 164  #ifdef __cplusplus
 165  
 166  #define CLAY__INIT(type) type
 167  
 168  #define CLAY_PACKED_ENUM enum : uint8_t
 169  
 170  #define CLAY__DEFAULT_STRUCT {}
 171  
 172  #else
 173  
 174  #define CLAY__INIT(type) (type)
 175  
 176  #if defined(_MSC_VER) && !defined(__clang__)
 177  #define CLAY_PACKED_ENUM __pragma(pack(push, 1)) enum __pragma(pack(pop))
 178  #else
 179  #define CLAY_PACKED_ENUM enum __attribute__((__packed__))
 180  #endif
 181  
 182  #if __STDC_VERSION__ >= 202311L
 183  #define CLAY__DEFAULT_STRUCT {}
 184  #else
 185  #define CLAY__DEFAULT_STRUCT {0}
 186  #endif
 187  
 188  #endif // __cplusplus
 189  
 190  #ifdef __cplusplus
 191  extern "C" {
 192  #endif
 193  
 194  // Utility Structs -------------------------
 195  
 196  // Note: Clay_String is not guaranteed to be null terminated. It may be if created from a literal C string,
 197  // but it is also used to represent slices.
 198  typedef struct Clay_String {
 199      // Set this boolean to true if the char* data underlying this string will live for the entire lifetime of the program.
 200      // This will automatically be set for strings created with CLAY_STRING, as the macro requires a string literal.
 201      bool isStaticallyAllocated;
 202      int32_t length;
 203      // The underlying character memory. Note: this will not be copied and will not extend the lifetime of the underlying memory.
 204      const char *chars;
 205  } Clay_String;
 206  
 207  // Clay_StringSlice is used to represent non owning string slices, and includes
 208  // a baseChars field which points to the string this slice is derived from.
 209  typedef struct Clay_StringSlice {
 210      int32_t length;
 211      const char *chars;
 212      const char *baseChars; // The source string / char* that this slice was derived from
 213  } Clay_StringSlice;
 214  
 215  typedef struct Clay_Context Clay_Context;
 216  
 217  // Clay_Arena is a memory arena structure that is used by clay to manage its internal allocations.
 218  // Rather than creating it by hand, it's easier to use Clay_CreateArenaWithCapacityAndMemory()
 219  typedef struct Clay_Arena {
 220      uintptr_t nextAllocation;
 221      size_t capacity;
 222      char *memory;
 223  } Clay_Arena;
 224  
 225  typedef struct Clay_Dimensions {
 226      float width, height;
 227  } Clay_Dimensions;
 228  
 229  typedef struct Clay_Vector2 {
 230      float x, y;
 231  } Clay_Vector2;
 232  
 233  // Internally clay conventionally represents colors as 0-255, but interpretation is up to the renderer.
 234  typedef struct Clay_Color {
 235      float r, g, b, a;
 236  } Clay_Color;
 237  
 238  typedef struct Clay_BoundingBox {
 239      float x, y, width, height;
 240  } Clay_BoundingBox;
 241  
 242  // Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
 243  // Represents a hashed string ID used for identifying and finding specific clay UI elements, required
 244  // by functions such as Clay_PointerOver() and Clay_GetElementData().
 245  typedef struct Clay_ElementId {
 246      uint32_t id; // The resulting hash generated from the other fields.
 247      uint32_t offset; // A numerical offset applied after computing the hash from stringId.
 248      uint32_t baseId; // A base hash value to start from, for example the parent element ID is used when calculating CLAY_ID_LOCAL().
 249      Clay_String stringId; // The string id to hash.
 250  } Clay_ElementId;
 251  
 252  // A sized array of Clay_ElementId.
 253  typedef struct
 254  {
 255      int32_t capacity;
 256      int32_t length;
 257      Clay_ElementId *internalArray;
 258  } Clay_ElementIdArray;
 259  
 260  // Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
 261  // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
 262  typedef struct Clay_CornerRadius {
 263      float topLeft;
 264      float topRight;
 265      float bottomLeft;
 266      float bottomRight;
 267  } Clay_CornerRadius;
 268  
 269  // Element Configs ---------------------------
 270  
 271  // Controls the direction in which child elements will be automatically laid out.
 272  typedef CLAY_PACKED_ENUM {
 273      // (Default) Lays out child elements from left to right with increasing x.
 274      CLAY_LEFT_TO_RIGHT,
 275      // Lays out child elements from top to bottom with increasing y.
 276      CLAY_TOP_TO_BOTTOM,
 277  } Clay_LayoutDirection;
 278  
 279  // Controls the alignment along the x axis (horizontal) of child elements.
 280  typedef CLAY_PACKED_ENUM {
 281      // (Default) Aligns child elements to the left hand side of this element, offset by padding.width.left
 282      CLAY_ALIGN_X_LEFT,
 283      // Aligns child elements to the right hand side of this element, offset by padding.width.right
 284      CLAY_ALIGN_X_RIGHT,
 285      // Aligns child elements horizontally to the center of this element
 286      CLAY_ALIGN_X_CENTER,
 287  } Clay_LayoutAlignmentX;
 288  
 289  // Controls the alignment along the y axis (vertical) of child elements.
 290  typedef CLAY_PACKED_ENUM {
 291      // (Default) Aligns child elements to the top of this element, offset by padding.width.top
 292      CLAY_ALIGN_Y_TOP,
 293      // Aligns child elements to the bottom of this element, offset by padding.width.bottom
 294      CLAY_ALIGN_Y_BOTTOM,
 295      // Aligns child elements vertically to the center of this element
 296      CLAY_ALIGN_Y_CENTER,
 297  } Clay_LayoutAlignmentY;
 298  
 299  // Controls how the element takes up space inside its parent container.
 300  typedef CLAY_PACKED_ENUM {
 301      // (default) Wraps tightly to the size of the element's contents.
 302      CLAY__SIZING_TYPE_FIT,
 303      // Expands along this axis to fill available space in the parent element, sharing it with other GROW elements.
 304      CLAY__SIZING_TYPE_GROW,
 305      // Expects 0-1 range. Clamps the axis size to a percent of the parent container's axis size minus padding and child gaps.
 306      CLAY__SIZING_TYPE_PERCENT,
 307      // Clamps the axis size to an exact size in pixels.
 308      CLAY__SIZING_TYPE_FIXED,
 309  } Clay__SizingType;
 310  
 311  // Controls how child elements are aligned on each axis.
 312  typedef struct Clay_ChildAlignment {
 313      Clay_LayoutAlignmentX x; // Controls alignment of children along the x axis.
 314      Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis.
 315  } Clay_ChildAlignment;
 316  
 317  // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to,
 318  // overriding sizing types such as FIT or GROW.
 319  typedef struct Clay_SizingMinMax {
 320      float min; // The smallest final size of the element on this axis will be this value in pixels.
 321      float max; // The largest final size of the element on this axis will be this value in pixels.
 322  } Clay_SizingMinMax;
 323  
 324  // Controls the sizing of this element along one axis inside its parent container.
 325  typedef struct Clay_SizingAxis {
 326      union {
 327          Clay_SizingMinMax minMax; // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to, overriding sizing types such as FIT or GROW.
 328          float percent; // Expects 0-1 range. Clamps the axis size to a percent of the parent container's axis size minus padding and child gaps.
 329      } size;
 330      Clay__SizingType type; // Controls how the element takes up space inside its parent container.
 331  } Clay_SizingAxis;
 332  
 333  // Controls the sizing of this element along one axis inside its parent container.
 334  typedef struct Clay_Sizing {
 335      Clay_SizingAxis width; // Controls the width sizing of the element, along the x axis.
 336      Clay_SizingAxis height;  // Controls the height sizing of the element, along the y axis.
 337  } Clay_Sizing;
 338  
 339  // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children
 340  // will be placed.
 341  typedef struct Clay_Padding {
 342      uint16_t left;
 343      uint16_t right;
 344      uint16_t top;
 345      uint16_t bottom;
 346  } Clay_Padding;
 347  
 348  CLAY__WRAPPER_STRUCT(Clay_Padding);
 349  
 350  // Controls various settings that affect the size and position of an element, as well as the sizes and positions
 351  // of any child elements.
 352  typedef struct Clay_LayoutConfig {
 353      Clay_Sizing sizing; // Controls the sizing of this element inside it's parent container, including FIT, GROW, PERCENT and FIXED sizing.
 354      Clay_Padding padding; // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children will be placed.
 355      uint16_t childGap; // Controls the gap in pixels between child elements along the layout axis (horizontal gap for LEFT_TO_RIGHT, vertical gap for TOP_TO_BOTTOM).
 356      Clay_ChildAlignment childAlignment; // Controls how child elements are aligned on each axis.
 357      Clay_LayoutDirection layoutDirection; // Controls the direction in which child elements will be automatically laid out.
 358  } Clay_LayoutConfig;
 359  
 360  CLAY__WRAPPER_STRUCT(Clay_LayoutConfig);
 361  
 362  extern Clay_LayoutConfig CLAY_LAYOUT_DEFAULT;
 363  
 364  // Controls how text "wraps", that is how it is broken into multiple lines when there is insufficient horizontal space.
 365  typedef CLAY_PACKED_ENUM {
 366      // (default) breaks on whitespace characters.
 367      CLAY_TEXT_WRAP_WORDS,
 368      // Don't break on space characters, only on newlines.
 369      CLAY_TEXT_WRAP_NEWLINES,
 370      // Disable text wrapping entirely.
 371      CLAY_TEXT_WRAP_NONE,
 372  } Clay_TextElementConfigWrapMode;
 373  
 374  // Controls how wrapped lines of text are horizontally aligned within the outer text bounding box.
 375  typedef CLAY_PACKED_ENUM {
 376      // (default) Horizontally aligns wrapped lines of text to the left hand side of their bounding box.
 377      CLAY_TEXT_ALIGN_LEFT,
 378      // Horizontally aligns wrapped lines of text to the center of their bounding box.
 379      CLAY_TEXT_ALIGN_CENTER,
 380      // Horizontally aligns wrapped lines of text to the right hand side of their bounding box.
 381      CLAY_TEXT_ALIGN_RIGHT,
 382  } Clay_TextAlignment;
 383  
 384  // Controls various functionality related to text elements.
 385  typedef struct Clay_TextElementConfig {
 386      // A pointer that will be transparently passed through to the resulting render command.
 387      void *userData;
 388      // The RGBA color of the font to render, conventionally specified as 0-255.
 389      Clay_Color textColor;
 390      // An integer transparently passed to Clay_MeasureText to identify the font to use.
 391      // The debug view will pass fontId = 0 for its internal text.
 392      uint16_t fontId;
 393      // Controls the size of the font. Handled by the function provided to Clay_MeasureText.
 394      uint16_t fontSize;
 395      // Controls extra horizontal spacing between characters. Handled by the function provided to Clay_MeasureText.
 396      uint16_t letterSpacing;
 397      // Controls additional vertical space between wrapped lines of text.
 398      uint16_t lineHeight;
 399      // Controls how text "wraps", that is how it is broken into multiple lines when there is insufficient horizontal space.
 400      // CLAY_TEXT_WRAP_WORDS (default) breaks on whitespace characters.
 401      // CLAY_TEXT_WRAP_NEWLINES doesn't break on space characters, only on newlines.
 402      // CLAY_TEXT_WRAP_NONE disables wrapping entirely.
 403      Clay_TextElementConfigWrapMode wrapMode;
 404      // Controls how wrapped lines of text are horizontally aligned within the outer text bounding box.
 405      // CLAY_TEXT_ALIGN_LEFT (default) - Horizontally aligns wrapped lines of text to the left hand side of their bounding box.
 406      // CLAY_TEXT_ALIGN_CENTER - Horizontally aligns wrapped lines of text to the center of their bounding box.
 407      // CLAY_TEXT_ALIGN_RIGHT - Horizontally aligns wrapped lines of text to the right hand side of their bounding box.
 408      Clay_TextAlignment textAlignment;
 409  } Clay_TextElementConfig;
 410  
 411  CLAY__WRAPPER_STRUCT(Clay_TextElementConfig);
 412  
 413  // Aspect Ratio --------------------------------
 414  
 415  // Controls various settings related to aspect ratio scaling element.
 416  typedef struct Clay_AspectRatioElementConfig {
 417      float aspectRatio; // A float representing the target "Aspect ratio" for an element, which is its final width divided by its final height.
 418  } Clay_AspectRatioElementConfig;
 419  
 420  CLAY__WRAPPER_STRUCT(Clay_AspectRatioElementConfig);
 421  
 422  // Image --------------------------------
 423  
 424  // Controls various settings related to image elements.
 425  typedef struct Clay_ImageElementConfig {
 426      void* imageData; // A transparent pointer used to pass image data through to the renderer.
 427  } Clay_ImageElementConfig;
 428  
 429  CLAY__WRAPPER_STRUCT(Clay_ImageElementConfig);
 430  
 431  // Floating -----------------------------
 432  
 433  // Controls where a floating element is offset relative to its parent element.
 434  // Note: see https://github.com/user-attachments/assets/b8c6dfaa-c1b1-41a4-be55-013473e4a6ce for a visual explanation.
 435  typedef CLAY_PACKED_ENUM {
 436      CLAY_ATTACH_POINT_LEFT_TOP,
 437      CLAY_ATTACH_POINT_LEFT_CENTER,
 438      CLAY_ATTACH_POINT_LEFT_BOTTOM,
 439      CLAY_ATTACH_POINT_CENTER_TOP,
 440      CLAY_ATTACH_POINT_CENTER_CENTER,
 441      CLAY_ATTACH_POINT_CENTER_BOTTOM,
 442      CLAY_ATTACH_POINT_RIGHT_TOP,
 443      CLAY_ATTACH_POINT_RIGHT_CENTER,
 444      CLAY_ATTACH_POINT_RIGHT_BOTTOM,
 445  } Clay_FloatingAttachPointType;
 446  
 447  // Controls where a floating element is offset relative to its parent element.
 448  typedef struct Clay_FloatingAttachPoints {
 449      Clay_FloatingAttachPointType element; // Controls the origin point on a floating element that attaches to its parent.
 450      Clay_FloatingAttachPointType parent; // Controls the origin point on the parent element that the floating element attaches to.
 451  } Clay_FloatingAttachPoints;
 452  
 453  // Controls how mouse pointer events like hover and click are captured or passed through to elements underneath a floating element.
 454  typedef CLAY_PACKED_ENUM {
 455      // (default) "Capture" the pointer event and don't allow events like hover and click to pass through to elements underneath.
 456      CLAY_POINTER_CAPTURE_MODE_CAPTURE,
 457      //    CLAY_POINTER_CAPTURE_MODE_PARENT, TODO pass pointer through to attached parent
 458      // Transparently pass through pointer events like hover and click to elements underneath the floating element.
 459      CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH,
 460  } Clay_PointerCaptureMode;
 461  
 462  // Controls which element a floating element is "attached" to (i.e. relative offset from).
 463  typedef CLAY_PACKED_ENUM {
 464      // (default) Disables floating for this element.
 465      CLAY_ATTACH_TO_NONE,
 466      // Attaches this floating element to its parent, positioned based on the .attachPoints and .offset fields.
 467      CLAY_ATTACH_TO_PARENT,
 468      // Attaches this floating element to an element with a specific ID, specified with the .parentId field. positioned based on the .attachPoints and .offset fields.
 469      CLAY_ATTACH_TO_ELEMENT_WITH_ID,
 470      // Attaches this floating element to the root of the layout, which combined with the .offset field provides functionality similar to "absolute positioning".
 471      CLAY_ATTACH_TO_ROOT,
 472  } Clay_FloatingAttachToElement;
 473  
 474  // Controls whether or not a floating element is clipped to the same clipping rectangle as the element it's attached to.
 475  typedef CLAY_PACKED_ENUM {
 476      // (default) - The floating element does not inherit clipping.
 477      CLAY_CLIP_TO_NONE,
 478      // The floating element is clipped to the same clipping rectangle as the element it's attached to.
 479      CLAY_CLIP_TO_ATTACHED_PARENT
 480  } Clay_FloatingClipToElement;
 481  
 482  // Controls various settings related to "floating" elements, which are elements that "float" above other elements, potentially overlapping their boundaries,
 483  // and not affecting the layout of sibling or parent elements.
 484  typedef struct Clay_FloatingElementConfig {
 485      // Offsets this floating element by the provided x,y coordinates from its attachPoints.
 486      Clay_Vector2 offset;
 487      // Expands the boundaries of the outer floating element without affecting its children.
 488      Clay_Dimensions expand;
 489      // When used in conjunction with .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, attaches this floating element to the element in the hierarchy with the provided ID.
 490      // Hint: attach the ID to the other element with .id = CLAY_ID("yourId"), and specify the id the same way, with .parentId = CLAY_ID("yourId").id
 491      uint32_t parentId;
 492      // Controls the z index of this floating element and all its children. Floating elements are sorted in ascending z order before output.
 493      // zIndex is also passed to the renderer for all elements contained within this floating element.
 494      int16_t zIndex;
 495      // Controls how mouse pointer events like hover and click are captured or passed through to elements underneath / behind a floating element.
 496      // Enum is of the form CLAY_ATTACH_POINT_foo_bar. See Clay_FloatingAttachPoints for more details.
 497      // Note: see <img src="https://github.com/user-attachments/assets/b8c6dfaa-c1b1-41a4-be55-013473e4a6ce />
 498      // and <img src="https://github.com/user-attachments/assets/ebe75e0d-1904-46b0-982d-418f929d1516 /> for a visual explanation.
 499      Clay_FloatingAttachPoints attachPoints;
 500      // Controls how mouse pointer events like hover and click are captured or passed through to elements underneath a floating element.
 501      // CLAY_POINTER_CAPTURE_MODE_CAPTURE (default) - "Capture" the pointer event and don't allow events like hover and click to pass through to elements underneath.
 502      // CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH - Transparently pass through pointer events like hover and click to elements underneath the floating element.
 503      Clay_PointerCaptureMode pointerCaptureMode;
 504      // Controls which element a floating element is "attached" to (i.e. relative offset from).
 505      // CLAY_ATTACH_TO_NONE (default) - Disables floating for this element.
 506      // CLAY_ATTACH_TO_PARENT - Attaches this floating element to its parent, positioned based on the .attachPoints and .offset fields.
 507      // CLAY_ATTACH_TO_ELEMENT_WITH_ID - Attaches this floating element to an element with a specific ID, specified with the .parentId field. positioned based on the .attachPoints and .offset fields.
 508      // CLAY_ATTACH_TO_ROOT - Attaches this floating element to the root of the layout, which combined with the .offset field provides functionality similar to "absolute positioning".
 509      Clay_FloatingAttachToElement attachTo;
 510      // Controls whether or not a floating element is clipped to the same clipping rectangle as the element it's attached to.
 511      // CLAY_CLIP_TO_NONE (default) - The floating element does not inherit clipping.
 512      // CLAY_CLIP_TO_ATTACHED_PARENT - The floating element is clipped to the same clipping rectangle as the element it's attached to.
 513      Clay_FloatingClipToElement clipTo;
 514  } Clay_FloatingElementConfig;
 515  
 516  CLAY__WRAPPER_STRUCT(Clay_FloatingElementConfig);
 517  
 518  // Custom -----------------------------
 519  
 520  // Controls various settings related to custom elements.
 521  typedef struct Clay_CustomElementConfig {
 522      // A transparent pointer through which you can pass custom data to the renderer.
 523      // Generates CUSTOM render commands.
 524      void* customData;
 525  } Clay_CustomElementConfig;
 526  
 527  CLAY__WRAPPER_STRUCT(Clay_CustomElementConfig);
 528  
 529  // Scroll -----------------------------
 530  
 531  // Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction.
 532  typedef struct Clay_ClipElementConfig {
 533      bool horizontal; // Clip overflowing elements on the X axis.
 534      bool vertical; // Clip overflowing elements on the Y axis.
 535      Clay_Vector2 childOffset; // Offsets the x,y positions of all child elements. Used primarily for scrolling containers.
 536  } Clay_ClipElementConfig;
 537  
 538  CLAY__WRAPPER_STRUCT(Clay_ClipElementConfig);
 539  
 540  // Border -----------------------------
 541  
 542  // Controls the widths of individual element borders.
 543  typedef struct Clay_BorderWidth {
 544      uint16_t left;
 545      uint16_t right;
 546      uint16_t top;
 547      uint16_t bottom;
 548      // Creates borders between each child element, depending on the .layoutDirection.
 549      // e.g. for LEFT_TO_RIGHT, borders will be vertical lines, and for TOP_TO_BOTTOM borders will be horizontal lines.
 550      // .betweenChildren borders will result in individual RECTANGLE render commands being generated.
 551      uint16_t betweenChildren;
 552  } Clay_BorderWidth;
 553  
 554  // Controls settings related to element borders.
 555  typedef struct Clay_BorderElementConfig {
 556      Clay_Color color; // Controls the color of all borders with width > 0. Conventionally represented as 0-255, but interpretation is up to the renderer.
 557      Clay_BorderWidth width; // Controls the widths of individual borders. At least one of these should be > 0 for a BORDER render command to be generated.
 558  } Clay_BorderElementConfig;
 559  
 560  CLAY__WRAPPER_STRUCT(Clay_BorderElementConfig);
 561  
 562  typedef struct {
 563      Clay_BoundingBox boundingBox;
 564      Clay_Color backgroundColor;
 565      Clay_Color overlayColor;
 566      Clay_Color borderColor;
 567      Clay_BorderWidth borderWidth;
 568  } Clay_TransitionData;
 569  
 570  typedef enum {
 571      CLAY_TRANSITION_STATE_IDLE,
 572      CLAY_TRANSITION_STATE_ENTERING,
 573      CLAY_TRANSITION_STATE_TRANSITIONING,
 574      CLAY_TRANSITION_STATE_EXITING,
 575  } Clay_TransitionState;
 576  
 577  typedef enum {
 578      CLAY_TRANSITION_PROPERTY_NONE = 0,
 579      CLAY_TRANSITION_PROPERTY_X = 1,
 580      CLAY_TRANSITION_PROPERTY_Y = 2,
 581      CLAY_TRANSITION_PROPERTY_POSITION = CLAY_TRANSITION_PROPERTY_X | CLAY_TRANSITION_PROPERTY_Y,
 582      CLAY_TRANSITION_PROPERTY_WIDTH = 4,
 583      CLAY_TRANSITION_PROPERTY_HEIGHT = 8,
 584      CLAY_TRANSITION_PROPERTY_DIMENSIONS = CLAY_TRANSITION_PROPERTY_WIDTH | CLAY_TRANSITION_PROPERTY_HEIGHT,
 585      CLAY_TRANSITION_PROPERTY_BOUNDING_BOX = CLAY_TRANSITION_PROPERTY_POSITION | CLAY_TRANSITION_PROPERTY_DIMENSIONS,
 586      CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR = 16,
 587      CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR = 32,
 588      CLAY_TRANSITION_PROPERTY_CORNER_RADIUS = 64,
 589      CLAY_TRANSITION_PROPERTY_BORDER_COLOR = 128,
 590      CLAY_TRANSITION_PROPERTY_BORDER_WIDTH = 256,
 591      CLAY_TRANSITION_PROPERTY_BORDER = CLAY_TRANSITION_PROPERTY_BORDER_COLOR | CLAY_TRANSITION_PROPERTY_BORDER_WIDTH
 592  } Clay_TransitionProperty;
 593  
 594  typedef struct {
 595      Clay_TransitionState transitionState;
 596      Clay_TransitionData initial;
 597      Clay_TransitionData *current;
 598      Clay_TransitionData target;
 599      float elapsedTime;
 600      float duration;
 601      Clay_TransitionProperty properties;
 602  } Clay_TransitionCallbackArguments;
 603  
 604  typedef CLAY_PACKED_ENUM {
 605      CLAY_TRANSITION_ENTER_SKIP_ON_FIRST_PARENT_FRAME,
 606      CLAY_TRANSITION_ENTER_TRIGGER_ON_FIRST_PARENT_FRAME,
 607  } Clay_TransitionEnterTriggerType;
 608  
 609  typedef CLAY_PACKED_ENUM {
 610      CLAY_TRANSITION_EXIT_SKIP_WHEN_PARENT_EXITS,
 611      CLAY_TRANSITION_EXIT_TRIGGER_WHEN_PARENT_EXITS,
 612  } Clay_TransitionExitTriggerType;
 613  
 614  typedef CLAY_PACKED_ENUM {
 615      CLAY_TRANSITION_DISABLE_INTERACTIONS_WHILE_TRANSITIONING_POSITION,
 616      CLAY_TRANSITION_ALLOW_INTERACTIONS_WHILE_TRANSITIONING_POSITION,
 617  } Clay_TransitionInteractionHandlingType;
 618  
 619  typedef CLAY_PACKED_ENUM {
 620      CLAY_EXIT_TRANSITION_ORDERING_UNDERNEATH_SIBLINGS,
 621      CLAY_EXIT_TRANSITION_ORDERING_NATURAL_ORDER,
 622      CLAY_EXIT_TRANSITION_ORDERING_ABOVE_SIBLINGS,
 623  } Clay_ExitTransitionSiblingOrdering;
 624  
 625  // Controls settings related to transitions
 626  typedef struct Clay_TransitionElementConfig {
 627      bool (*handler)(Clay_TransitionCallbackArguments arguments);
 628      float duration;
 629      Clay_TransitionProperty properties;
 630      Clay_TransitionInteractionHandlingType interactionHandling;
 631      struct {
 632          Clay_TransitionData (*setInitialState)(Clay_TransitionData targetState, Clay_TransitionProperty properties);
 633          Clay_TransitionEnterTriggerType trigger;
 634      } enter;
 635      struct {
 636          Clay_TransitionData (*setFinalState)(Clay_TransitionData initialState, Clay_TransitionProperty properties);
 637          Clay_TransitionExitTriggerType trigger;
 638          Clay_ExitTransitionSiblingOrdering siblingOrdering;
 639      } exit;
 640  } Clay_TransitionElementConfig;
 641  
 642  CLAY__WRAPPER_STRUCT(Clay_TransitionElementConfig);
 643  
 644  // Render Command Data -----------------------------
 645  
 646  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
 647  typedef struct Clay_TextRenderData {
 648      // A string slice containing the text to be rendered.
 649      // Note: this is not guaranteed to be null terminated.
 650      Clay_StringSlice stringContents;
 651      // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
 652      Clay_Color textColor;
 653      // An integer representing the font to use to render this text, transparently passed through from the text declaration.
 654      uint16_t fontId;
 655      uint16_t fontSize;
 656      // Specifies the extra whitespace gap in pixels between each character.
 657      uint16_t letterSpacing;
 658      // The height of the bounding box for this line of text.
 659      uint16_t lineHeight;
 660  } Clay_TextRenderData;
 661  
 662  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
 663  typedef struct Clay_RectangleRenderData {
 664      // The solid background color to fill this rectangle with. Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
 665      Clay_Color backgroundColor;
 666      // Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
 667      // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
 668      Clay_CornerRadius cornerRadius;
 669  } Clay_RectangleRenderData;
 670  
 671  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE
 672  typedef struct Clay_ImageRenderData {
 673      // The tint color for this image. Note that the default value is 0,0,0,0 and should likely be interpreted
 674      // as "untinted".
 675      // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
 676      Clay_Color backgroundColor;
 677      // Controls the "radius", or corner rounding of this image.
 678      // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
 679      Clay_CornerRadius cornerRadius;
 680      // A pointer transparently passed through from the original element definition, typically used to represent image data.
 681      void* imageData;
 682  } Clay_ImageRenderData;
 683  
 684  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM
 685  typedef struct Clay_CustomRenderData {
 686      // Passed through from .backgroundColor in the original element declaration.
 687      // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
 688      Clay_Color backgroundColor;
 689      // Controls the "radius", or corner rounding of this custom element.
 690      // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
 691      Clay_CornerRadius cornerRadius;
 692      // A pointer transparently passed through from the original element definition.
 693      void* customData;
 694  } Clay_CustomRenderData;
 695  
 696  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_END
 697  typedef struct Clay_ClipRenderData {
 698      bool horizontal;
 699      bool vertical;
 700  } Clay_ClipRenderData;
 701  
 702  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_END
 703  typedef struct Clay_OverlayColorRenderData {
 704      Clay_Color color;
 705  } Clay_OverlayColorRenderData;
 706  
 707  // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER
 708  typedef struct Clay_BorderRenderData {
 709      // Controls a shared color for all this element's borders.
 710      // Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
 711      Clay_Color color;
 712      // Specifies the "radius", or corner rounding of this border element.
 713      // The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
 714      Clay_CornerRadius cornerRadius;
 715      // Controls individual border side widths.
 716      Clay_BorderWidth width;
 717  } Clay_BorderRenderData;
 718  
 719  // A struct union containing data specific to this command's .commandType
 720  typedef union Clay_RenderData {
 721      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
 722      Clay_RectangleRenderData rectangle;
 723      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
 724      Clay_TextRenderData text;
 725      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE
 726      Clay_ImageRenderData image;
 727      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM
 728      Clay_CustomRenderData custom;
 729      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER
 730      Clay_BorderRenderData border;
 731      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START|END
 732      Clay_ClipRenderData clip;
 733      // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_START|END
 734      Clay_OverlayColorRenderData overlayColor;
 735  } Clay_RenderData;
 736  
 737  // Miscellaneous Structs & Enums ---------------------------------
 738  
 739  // Data representing the current internal state of a scrolling element.
 740  typedef struct Clay_ScrollContainerData {
 741      // Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout.
 742      // Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
 743      Clay_Vector2 *scrollPosition;
 744      // The bounding box of the scroll element.
 745      Clay_Dimensions scrollContainerDimensions;
 746      // The outer dimensions of the inner scroll container content, including the padding of the parent scroll container.
 747      Clay_Dimensions contentDimensions;
 748      // The config that was originally passed to the clip element.
 749      Clay_ClipElementConfig config;
 750      // Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
 751      bool found;
 752  } Clay_ScrollContainerData;
 753  
 754  // Bounding box and other data for a specific UI element.
 755  typedef struct Clay_ElementData {
 756      // The rectangle that encloses this UI element, with the position relative to the root of the layout.
 757      Clay_BoundingBox boundingBox;
 758      // Indicates whether an actual Element matched the provided ID or if the default struct was returned.
 759      bool found;
 760  } Clay_ElementData;
 761  
 762  // Used by renderers to determine specific handling for each render command.
 763  typedef CLAY_PACKED_ENUM {
 764      // This command type should be skipped.
 765      CLAY_RENDER_COMMAND_TYPE_NONE,
 766      // The renderer should draw a solid color rectangle.
 767      CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
 768      // The renderer should draw a colored border inset into the bounding box.
 769      CLAY_RENDER_COMMAND_TYPE_BORDER,
 770      // The renderer should draw text.
 771      CLAY_RENDER_COMMAND_TYPE_TEXT,
 772      // The renderer should draw an image.
 773      CLAY_RENDER_COMMAND_TYPE_IMAGE,
 774      // The renderer should begin clipping all future draw commands, only rendering content that falls within the provided boundingBox.
 775      CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
 776      // The renderer should finish any previously active clipping, and begin rendering elements in full again.
 777      CLAY_RENDER_COMMAND_TYPE_SCISSOR_END,
 778      // The renderer should begin performing a "color overlay" on all subsequent render commands until disabled again.
 779      CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_START,
 780      // The renderer should disable any previously active "color overlay" and render elements with their standard colors again.
 781      CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_END,
 782      // The renderer should provide a custom implementation for handling this render command based on its .customData
 783      CLAY_RENDER_COMMAND_TYPE_CUSTOM,
 784  } Clay_RenderCommandType;
 785  
 786  typedef struct Clay_RenderCommand {
 787      // A rectangular box that fully encloses this UI element, with the position relative to the root of the layout.
 788      Clay_BoundingBox boundingBox;
 789      // A struct union containing data specific to this command's commandType.
 790      Clay_RenderData renderData;
 791      // A pointer transparently passed through from the original element declaration.
 792      void *userData;
 793      // The id of this element, transparently passed through from the original element declaration.
 794      uint32_t id;
 795      // The z order required for drawing this command correctly.
 796      // Note: the render command array is already sorted in ascending order, and will produce correct results if drawn in naive order.
 797      // This field is intended for use in batching renderers for improved performance.
 798      int16_t zIndex;
 799      // Specifies how to handle rendering of this command.
 800      // CLAY_RENDER_COMMAND_TYPE_RECTANGLE - The renderer should draw a solid color rectangle.
 801      // CLAY_RENDER_COMMAND_TYPE_BORDER - The renderer should draw a colored border inset into the bounding box.
 802      // CLAY_RENDER_COMMAND_TYPE_TEXT - The renderer should draw text.
 803      // CLAY_RENDER_COMMAND_TYPE_IMAGE - The renderer should draw an image.
 804      // CLAY_RENDER_COMMAND_TYPE_SCISSOR_START - The renderer should begin clipping all future draw commands, only rendering content that falls within the provided boundingBox.
 805      // CLAY_RENDER_COMMAND_TYPE_SCISSOR_END - The renderer should finish any previously active clipping, and begin rendering elements in full again.
 806      // CLAY_RENDER_COMMAND_TYPE_CUSTOM - The renderer should provide a custom implementation for handling this render command based on its .customData
 807      Clay_RenderCommandType commandType;
 808  } Clay_RenderCommand;
 809  
 810  // A sized array of render commands.
 811  typedef struct Clay_RenderCommandArray {
 812      // The underlying max capacity of the array, not necessarily all initialized.
 813      int32_t capacity;
 814      // The number of initialized elements in this array. Used for loops and iteration.
 815      int32_t length;
 816      // A pointer to the first element in the internal array.
 817      Clay_RenderCommand* internalArray;
 818  } Clay_RenderCommandArray;
 819  
 820  // Represents the current state of interaction with clay this frame.
 821  typedef CLAY_PACKED_ENUM {
 822      // A left mouse click, or touch occurred this frame.
 823      CLAY_POINTER_DATA_PRESSED_THIS_FRAME,
 824      // The left mouse button click or touch happened at some point in the past, and is still currently held down this frame.
 825      CLAY_POINTER_DATA_PRESSED,
 826      // The left mouse button click or touch was released this frame.
 827      CLAY_POINTER_DATA_RELEASED_THIS_FRAME,
 828      // The left mouse button click or touch is not currently down / was released at some point in the past.
 829      CLAY_POINTER_DATA_RELEASED,
 830  } Clay_PointerDataInteractionState;
 831  
 832  // Information on the current state of pointer interactions this frame.
 833  typedef struct Clay_PointerData {
 834      // The position of the mouse / touch / pointer relative to the root of the layout.
 835      Clay_Vector2 position;
 836      // Represents the current state of interaction with clay this frame.
 837      // CLAY_POINTER_DATA_PRESSED_THIS_FRAME - A left mouse click, or touch occurred this frame.
 838      // CLAY_POINTER_DATA_PRESSED - The left mouse button click or touch happened at some point in the past, and is still currently held down this frame.
 839      // CLAY_POINTER_DATA_RELEASED_THIS_FRAME - The left mouse button click or touch was released this frame.
 840      // CLAY_POINTER_DATA_RELEASED - The left mouse button click or touch is not currently down / was released at some point in the past.
 841      Clay_PointerDataInteractionState state;
 842  } Clay_PointerData;
 843  
 844  typedef struct Clay_ElementDeclaration {
 845      // Controls various settings that affect the size and position of an element, as well as the sizes and positions of any child elements.
 846      Clay_LayoutConfig layout;
 847      // Controls the background color of the resulting element.
 848      // By convention specified as 0-255, but interpretation is up to the renderer.
 849      // If no other config is specified, .backgroundColor will generate a RECTANGLE render command, otherwise it will be passed as a property to IMAGE or CUSTOM render commands.
 850      Clay_Color backgroundColor;
 851      // Perform an image editing style "Color Overlay" on this element and all its children, equivalent to
 852      // glsl mix(elementColor, overlayColor.rgb, overlayColor.a)
 853      Clay_Color overlayColor;
 854      // Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
 855      Clay_CornerRadius cornerRadius;
 856      // Controls settings related to aspect ratio scaling.
 857      Clay_AspectRatioElementConfig aspectRatio;
 858      // Controls settings related to image elements.
 859      Clay_ImageElementConfig image;
 860      // Controls whether and how an element "floats", which means it layers over the top of other elements in z order, and doesn't affect the position and size of siblings or parent elements.
 861      // Note: in order to activate floating, .floating.attachTo must be set to something other than the default value.
 862      Clay_FloatingElementConfig floating;
 863      // Used to create CUSTOM render commands, usually to render element types not supported by Clay.
 864      Clay_CustomElementConfig custom;
 865      // Controls whether an element should clip its contents, as well as providing child x,y offset configuration for scrolling.
 866      Clay_ClipElementConfig clip;
 867      // Controls settings related to element borders, and will generate BORDER render commands.
 868      Clay_BorderElementConfig border;
 869      Clay_TransitionElementConfig transition;
 870      // A pointer that will be transparently passed through to resulting render commands.
 871      void *userData;
 872  } Clay_ElementDeclaration;
 873  
 874  CLAY__WRAPPER_STRUCT(Clay_ElementDeclaration);
 875  
 876  // Represents the type of error clay encountered while computing layout.
 877  typedef CLAY_PACKED_ENUM {
 878      // A text measurement function wasn't provided using Clay_SetMeasureTextFunction(), or the provided function was null.
 879      CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
 880      // Clay attempted to allocate its internal data structures but ran out of space.
 881      // The arena passed to Clay_Initialize was created with a capacity smaller than that required by Clay_MinMemorySize().
 882      CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
 883      // Clay ran out of capacity in its internal array for storing elements. This limit can be increased with Clay_SetMaxElementCount().
 884      CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
 885      // Clay ran out of capacity in its internal array for storing elements. This limit can be increased with Clay_SetMaxMeasureTextCacheWordCount().
 886      CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
 887      // Two elements were declared with exactly the same ID within one layout.
 888      CLAY_ERROR_TYPE_DUPLICATE_ID,
 889      // A floating element was declared using CLAY_ATTACH_TO_ELEMENT_ID and either an invalid .parentId was provided or no element with the provided .parentId was found.
 890      CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND,
 891      // An element was declared that using CLAY_SIZING_PERCENT but the percentage value was over 1. Percentage values are expected to be in the 0-1 range.
 892      CLAY_ERROR_TYPE_PERCENTAGE_OVER_1,
 893      // Clay encountered an internal error. It would be wonderful if you could report this so we can fix it!
 894      CLAY_ERROR_TYPE_INTERNAL_ERROR,
 895      // Clay__OpenElement was called more times than Clay__CloseElement, so there were still remaining open elements when the layout ended.
 896      CLAY_ERROR_TYPE_UNBALANCED_OPEN_CLOSE,
 897  } Clay_ErrorType;
 898  
 899  // Data to identify the error that clay has encountered.
 900  typedef struct Clay_ErrorData {
 901      // Represents the type of error clay encountered while computing layout.
 902      // CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED - A text measurement function wasn't provided using Clay_SetMeasureTextFunction(), or the provided function was null.
 903      // CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED - Clay attempted to allocate its internal data structures but ran out of space. The arena passed to Clay_Initialize was created with a capacity smaller than that required by Clay_MinMemorySize().
 904      // CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED - Clay ran out of capacity in its internal array for storing elements. This limit can be increased with Clay_SetMaxElementCount().
 905      // CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED - Clay ran out of capacity in its internal array for storing elements. This limit can be increased with Clay_SetMaxMeasureTextCacheWordCount().
 906      // CLAY_ERROR_TYPE_DUPLICATE_ID - Two elements were declared with exactly the same ID within one layout.
 907      // CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND - A floating element was declared using CLAY_ATTACH_TO_ELEMENT_ID and either an invalid .parentId was provided or no element with the provided .parentId was found.
 908      // CLAY_ERROR_TYPE_PERCENTAGE_OVER_1 - An element was declared that using CLAY_SIZING_PERCENT but the percentage value was over 1. Percentage values are expected to be in the 0-1 range.
 909      // CLAY_ERROR_TYPE_INTERNAL_ERROR - Clay encountered an internal error. It would be wonderful if you could report this so we can fix it!
 910      Clay_ErrorType errorType;
 911      // A string containing human-readable error text that explains the error in more detail.
 912      Clay_String errorText;
 913      // A transparent pointer passed through from when the error handler was first provided.
 914      void *userData;
 915  } Clay_ErrorData;
 916  
 917  // A wrapper struct around Clay's error handler function.
 918  typedef struct {
 919      // A user provided function to call when Clay encounters an error during layout.
 920      void (*errorHandlerFunction)(Clay_ErrorData errorText);
 921      // A pointer that will be transparently passed through to the error handler when it is called.
 922      void *userData;
 923  } Clay_ErrorHandler;
 924  
 925  // Function Forward Declarations ---------------------------------
 926  
 927  // Public API functions ------------------------------------------
 928  
 929  // Returns the size, in bytes, of the minimum amount of memory Clay requires to operate at its current settings.
 930  CLAY_DLL_EXPORT uint32_t Clay_MinMemorySize(void);
 931  // Creates an arena for clay to use for its internal allocations, given a certain capacity in bytes and a pointer to an allocation of at least that size.
 932  // Intended to be used with Clay_MinMemorySize in the following way:
 933  // uint32_t minMemoryRequired = Clay_MinMemorySize();
 934  // Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(minMemoryRequired, malloc(minMemoryRequired));
 935  CLAY_DLL_EXPORT Clay_Arena Clay_CreateArenaWithCapacityAndMemory(size_t capacity, void *memory);
 936  // Sets the state of the "pointer" (i.e. the mouse or touch) in Clay's internal data. Used for detecting and responding to mouse events in the debug view,
 937  // as well as for Clay_Hovered() and scroll element handling.
 938  CLAY_DLL_EXPORT void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
 939  // Returns the state of the "pointer" (i.e. the mouse or touch) which was set via Clay_SetPointerState().
 940  CLAY_DLL_EXPORT Clay_PointerData Clay_GetPointerState(void);
 941  // Initialize Clay's internal arena and setup required data before layout can begin. Only needs to be called once.
 942  // - arena can be created using Clay_CreateArenaWithCapacityAndMemory()
 943  // - layoutDimensions are the initial bounding dimensions of the layout (i.e. the screen width and height for a full screen layout)
 944  // - errorHandler is used by Clay to inform you if something has gone wrong in configuration or layout.
 945  CLAY_DLL_EXPORT Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
 946  // Returns the Context that clay is currently using. Used when using multiple instances of clay simultaneously.
 947  CLAY_DLL_EXPORT Clay_Context* Clay_GetCurrentContext(void);
 948  // Sets the context that clay will use to compute the layout.
 949  // Used to restore a context saved from Clay_GetCurrentContext when using multiple instances of clay simultaneously.
 950  CLAY_DLL_EXPORT void Clay_SetCurrentContext(Clay_Context* context);
 951  // Updates the state of Clay's internal scroll data, updating scroll content positions if scrollDelta is non zero, and progressing momentum scrolling.
 952  // - enableDragScrolling when set to true will enable mobile device like "touch drag" scroll of scroll containers, including momentum scrolling after the touch has ended.
 953  // - scrollDelta is the amount to scroll this frame on each axis in pixels.
 954  // - deltaTime is the time in seconds since the last "frame" (scroll update)
 955  CLAY_DLL_EXPORT void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
 956  // Returns the internally stored scroll offset for the currently open element.
 957  // Generally intended for use with clip elements to create scrolling containers.
 958  CLAY_DLL_EXPORT Clay_Vector2 Clay_GetScrollOffset(void);
 959  // Updates the layout dimensions in response to the window or outer container being resized.
 960  CLAY_DLL_EXPORT void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
 961  // Called before starting any layout declarations.
 962  CLAY_DLL_EXPORT void Clay_BeginLayout(void);
 963  // Called when all layout declarations are finished.
 964  // Computes the layout and generates and returns the array of render commands to draw.
 965  CLAY_DLL_EXPORT Clay_RenderCommandArray Clay_EndLayout(float deltaTime);
 966  // Gets the ID of the currently open element, useful for retrieving IDs generated by CLAY_AUTO_ID()
 967  CLAY_DLL_EXPORT uint32_t Clay_GetOpenElementId(void);
 968  // Calculates a hash ID from the given idString.
 969  // Generally only used for dynamic strings when CLAY_ID("stringLiteral") can't be used.
 970  CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementId(Clay_String idString);
 971  // Calculates a hash ID from the given idString and index.
 972  // - index is used to avoid constructing dynamic ID strings in loops.
 973  // Generally only used for dynamic strings when CLAY_IDI("stringLiteral", index) can't be used.
 974  CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index);
 975  // Returns layout data such as the final calculated bounding box for an element with a given ID.
 976  // The returned Clay_ElementData contains a `found` bool that will be true if an element with the provided ID was found.
 977  // This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
 978  CLAY_DLL_EXPORT Clay_ElementData Clay_GetElementData(Clay_ElementId id);
 979  // Returns true if the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
 980  // Works during element declaration, e.g. CLAY({ .backgroundColor = Clay_Hovered() ? BLUE : RED });
 981  CLAY_DLL_EXPORT bool Clay_Hovered(void);
 982  // Bind a callback that will be called when the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
 983  // - onHoverFunction is a function pointer to a user defined function.
 984  // - userData is a pointer that will be transparently passed through when the onHoverFunction is called.
 985  CLAY_DLL_EXPORT void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, void *userData), void *userData);
 986  // An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
 987  // This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
 988  CLAY_DLL_EXPORT bool Clay_PointerOver(Clay_ElementId elementId);
 989  // Returns the array of element IDs that the pointer is currently over.
 990  CLAY_DLL_EXPORT Clay_ElementIdArray Clay_GetPointerOverIds(void);
 991  // Returns data representing the state of the scrolling element with the provided ID.
 992  // The returned Clay_ScrollContainerData contains a `found` bool that will be true if a scroll element was found with the provided ID.
 993  // An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
 994  // This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
 995  CLAY_DLL_EXPORT Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
 996  // Binds a callback function that Clay will call to determine the dimensions of a given string slice.
 997  // - measureTextFunction is a user provided function that adheres to the interface Clay_Dimensions (Clay_StringSlice text, Clay_TextElementConfig *config, void *userData);
 998  // - userData is a pointer that will be transparently passed through when the measureTextFunction is called.
 999  CLAY_DLL_EXPORT void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData);
1000  // Experimental - Used in cases where Clay needs to integrate with a system that manages its own scrolling containers externally.
1001  // Please reach out if you plan to use this function, as it may be subject to change.
1002  CLAY_DLL_EXPORT void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData);
1003  // A bounds-checked "get" function for the Clay_RenderCommandArray returned from Clay_EndLayout().
1004  CLAY_DLL_EXPORT Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
1005  // Enables and disables Clay's internal debug tools.
1006  // This state is retained and does not need to be set each frame.
1007  CLAY_DLL_EXPORT void Clay_SetDebugModeEnabled(bool enabled);
1008  // Returns true if Clay's internal debug tools are currently enabled.
1009  CLAY_DLL_EXPORT bool Clay_IsDebugModeEnabled(void);
1010  // Enables and disables visibility culling. By default, Clay will not generate render commands for elements whose bounding box is entirely outside the screen.
1011  CLAY_DLL_EXPORT void Clay_SetCullingEnabled(bool enabled);
1012  // Returns the maximum number of UI elements supported by Clay's current configuration.
1013  CLAY_DLL_EXPORT int32_t Clay_GetMaxElementCount(void);
1014  // Modifies the maximum number of UI elements supported by Clay's current configuration.
1015  // This may require reallocating additional memory, and re-calling Clay_Initialize();
1016  CLAY_DLL_EXPORT void Clay_SetMaxElementCount(int32_t maxElementCount);
1017  // Returns the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
1018  CLAY_DLL_EXPORT int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
1019  // Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
1020  // This may require reallocating additional memory, and re-calling Clay_Initialize();
1021  CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
1022  // Resets Clay's internal text measurement cache. Useful if font mappings have changed or fonts have been reloaded.
1023  CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void);
1024  // A built in transition function that uses the "Ease Out" curve
1025  CLAY_DLL_EXPORT bool Clay_EaseOut(Clay_TransitionCallbackArguments arguments);
1026  
1027  // Internal API functions required by macros ----------------------
1028  
1029  CLAY_DLL_EXPORT void Clay__OpenElement(void);
1030  CLAY_DLL_EXPORT void Clay__OpenElementWithId(Clay_ElementId elementId);
1031  CLAY_DLL_EXPORT void Clay__ConfigureOpenElement(const Clay_ElementDeclaration config);
1032  CLAY_DLL_EXPORT void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *config);
1033  CLAY_DLL_EXPORT void Clay__CloseElement(void);
1034  CLAY_DLL_EXPORT Clay_ElementId Clay__HashString(Clay_String key, uint32_t seed);
1035  CLAY_DLL_EXPORT Clay_ElementId Clay__HashStringWithOffset(Clay_String key, uint32_t offset, uint32_t seed);
1036  CLAY_DLL_EXPORT void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig textConfig);
1037  
1038  extern Clay_Color Clay__debugViewHighlightColor;
1039  extern uint32_t Clay__debugViewWidth;
1040  
1041  #ifdef __cplusplus
1042  }
1043  #endif
1044  
1045  #endif // CLAY_HEADER
1046  
1047  // -----------------------------------------
1048  // IMPLEMENTATION --------------------------
1049  // -----------------------------------------
1050  #ifdef CLAY_IMPLEMENTATION
1051  #undef CLAY_IMPLEMENTATION
1052  
1053  #ifndef CLAY__NULL
1054  #define CLAY__NULL 0
1055  #endif
1056  
1057  #ifndef CLAY__MAXFLOAT
1058  #define CLAY__MAXFLOAT 3.40282346638528859812e+38F
1059  #endif
1060  
1061  Clay_LayoutConfig CLAY_LAYOUT_DEFAULT = CLAY__DEFAULT_STRUCT;
1062  
1063  Clay_Color Clay__Color_DEFAULT = CLAY__DEFAULT_STRUCT;
1064  Clay_CornerRadius Clay__CornerRadius_DEFAULT = CLAY__DEFAULT_STRUCT;
1065  Clay_BorderWidth Clay__BorderWidth_DEFAULT = CLAY__DEFAULT_STRUCT;
1066  
1067  // The below functions define array bounds checking and convenience functions for a provided type.
1068  #define CLAY__ARRAY_DEFINE_FUNCTIONS(typeName, arrayName)                                                       \
1069                                                                                                                  \
1070  typedef struct                                                                                                  \
1071  {                                                                                                               \
1072      int32_t length;                                                                                             \
1073      typeName *internalArray;                                                                                    \
1074  } arrayName##Slice;                                                                                             \
1075                                                                                                                  \
1076  typeName typeName##_DEFAULT = CLAY__DEFAULT_STRUCT;                                                             \
1077                                                                                                                  \
1078  arrayName arrayName##_Allocate_Arena(int32_t capacity, Clay_Arena *arena) {                                     \
1079      return CLAY__INIT(arrayName){.capacity = capacity, .length = 0,                                             \
1080          .internalArray = (typeName *)Clay__Array_Allocate_Arena(capacity, sizeof(typeName), arena)};            \
1081  }                                                                                                               \
1082                                                                                                                  \
1083  typeName *arrayName##_Get(arrayName *array, int32_t index) {                                                    \
1084      return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : &typeName##_DEFAULT;   \
1085  }                                                                                                               \
1086                                                                                                                  \
1087  typeName arrayName##_GetValue(arrayName *array, int32_t index) {                                                \
1088      return Clay__Array_RangeCheck(index, array->length) ? array->internalArray[index] : typeName##_DEFAULT;     \
1089  }                                                                                                               \
1090                                                                                                                  \
1091  typeName *arrayName##_GetCheckCapacity(arrayName *array, int32_t index) {                                                    \
1092      return Clay__Array_RangeCheck(index, array->capacity) ? &array->internalArray[index] : &typeName##_DEFAULT;   \
1093  }                                                                                                               \
1094                                                                                                                  \
1095  typeName *arrayName##_Add(arrayName *array, typeName item) {                                                    \
1096      if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {                                         \
1097          array->internalArray[array->length++] = item;                                                           \
1098          return &array->internalArray[array->length - 1];                                                        \
1099      }                                                                                                           \
1100      return &typeName##_DEFAULT;                                                                                 \
1101  }                                                                                                               \
1102                                                                                                                  \
1103  typeName *arrayName##Slice_Get(arrayName##Slice *slice, int32_t index) {                                        \
1104      return Clay__Array_RangeCheck(index, slice->length) ? &slice->internalArray[index] : &typeName##_DEFAULT;   \
1105  }                                                                                                               \
1106                                                                                                                  \
1107  typeName arrayName##_RemoveSwapback(arrayName *array, int32_t index) {                                          \
1108  	if (Clay__Array_RangeCheck(index, array->length)) {                                                         \
1109  		array->length--;                                                                                        \
1110  		typeName removed = array->internalArray[index];                                                         \
1111  		array->internalArray[index] = array->internalArray[array->length];                                      \
1112  		return removed;                                                                                         \
1113  	}                                                                                                           \
1114  	return typeName##_DEFAULT;                                                                                  \
1115  }                                                                                                               \
1116                                                                                                                  \
1117  typeName* arrayName##_Set(arrayName *array, int32_t index, typeName value) {                                    \
1118  	if (Clay__Array_RangeCheck(index, array->capacity)) {                                                       \
1119  		array->internalArray[index] = value;                                                                    \
1120  		array->length = index < array->length ? array->length : index + 1;                                      \
1121          return &array->internalArray[index];\
1122  	}                                                                                                           \
1123      return NULL;\
1124  }                                                                                                               \
1125                                                                                                                  \
1126  typeName* arrayName##_Set_DontTouchLength(arrayName *array, int32_t index, typeName value) {                                    \
1127  	if (Clay__Array_RangeCheck(index, array->capacity)) {                                                       \
1128  		array->internalArray[index] = value;                                                                    \
1129          return &array->internalArray[index];\
1130  	}                                                                                                           \
1131      return NULL;\
1132  }  \
1133  
1134  #define CLAY__ARRAY_DEFINE(typeName, arrayName)     \
1135  typedef struct                                      \
1136  {                                                   \
1137      int32_t capacity;                               \
1138      int32_t length;                                 \
1139      typeName *internalArray;                        \
1140  } arrayName;                                        \
1141                                                      \
1142  CLAY__ARRAY_DEFINE_FUNCTIONS(typeName, arrayName)   \
1143  
1144  Clay_Context *Clay__currentContext;
1145  int32_t Clay__defaultMaxElementCount = 8192;
1146  int32_t Clay__defaultMaxMeasureTextWordCacheCount = 16384;
1147  
1148  void Clay__ErrorHandlerFunctionDefault(Clay_ErrorData errorText) {
1149      (void) errorText;
1150  }
1151  
1152  Clay_String CLAY__SPACECHAR = { .length = 1, .chars = " " };
1153  Clay_String CLAY__STRING_DEFAULT = { .length = 0, .chars = NULL };
1154  
1155  typedef struct {
1156      bool maxElementsExceeded;
1157      bool maxRenderCommandsExceeded;
1158      bool maxTextMeasureCacheExceeded;
1159      bool textMeasurementFunctionNotSet;
1160  } Clay_BooleanWarnings;
1161  
1162  typedef struct {
1163      Clay_String baseMessage;
1164      Clay_String dynamicMessage;
1165  } Clay__Warning;
1166  
1167  Clay__Warning CLAY__WARNING_DEFAULT = CLAY__DEFAULT_STRUCT;
1168  
1169  typedef struct {
1170      int32_t capacity;
1171      int32_t length;
1172      Clay__Warning *internalArray;
1173  } Clay__WarningArray;
1174  
1175  Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Arena *arena);
1176  Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item);
1177  void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, Clay_Arena *arena);
1178  bool Clay__Array_RangeCheck(int32_t index, int32_t length);
1179  bool Clay__Array_AddCapacityCheck(int32_t length, int32_t capacity);
1180  
1181  CLAY__ARRAY_DEFINE(bool, Clay__boolArray)
1182  CLAY__ARRAY_DEFINE(int32_t, Clay__int32_tArray)
1183  CLAY__ARRAY_DEFINE(char, Clay__charArray)
1184  CLAY__ARRAY_DEFINE_FUNCTIONS(Clay_ElementId, Clay_ElementIdArray)
1185  CLAY__ARRAY_DEFINE(Clay_String, Clay__StringArray)
1186  CLAY__ARRAY_DEFINE_FUNCTIONS(Clay_RenderCommand, Clay_RenderCommandArray)
1187  
1188  typedef struct {
1189      Clay_Dimensions dimensions;
1190      Clay_String line;
1191  } Clay__WrappedTextLine;
1192  
1193  CLAY__ARRAY_DEFINE(Clay__WrappedTextLine, Clay__WrappedTextLineArray)
1194  
1195  typedef struct {
1196      Clay_String text;
1197      Clay_Dimensions preferredDimensions;
1198      Clay__WrappedTextLineArraySlice wrappedLines;
1199  } Clay__TextElementData;
1200  
1201  typedef struct {
1202      int32_t *elements;
1203      uint16_t length;
1204  } Clay__LayoutElementChildren;
1205  
1206  typedef struct Clay_LayoutElement {
1207      Clay__LayoutElementChildren children;
1208      Clay_Dimensions dimensions;
1209      Clay_Dimensions minDimensions;
1210      union {
1211          Clay_ElementDeclaration config;
1212          struct {
1213              Clay_TextElementConfig textConfig;
1214              Clay__TextElementData textElementData;
1215          };
1216      };
1217      uint32_t id;
1218      uint16_t floatingChildrenCount;
1219      bool isTextElement;
1220      // True if the element is currently in an exit transition, and is "synthetic"
1221      // i.e. data was retained from previous frames
1222      bool exiting;
1223  } Clay_LayoutElement;
1224  
1225  CLAY__ARRAY_DEFINE(Clay_LayoutElement, Clay_LayoutElementArray)
1226  
1227  typedef struct {
1228      Clay_LayoutElement *layoutElement;
1229      Clay_BoundingBox boundingBox;
1230      Clay_Dimensions contentSize;
1231      Clay_Vector2 scrollOrigin;
1232      Clay_Vector2 pointerOrigin;
1233      Clay_Vector2 scrollMomentum;
1234      Clay_Vector2 scrollPosition;
1235      Clay_Vector2 previousDelta;
1236      float momentumTime;
1237      uint32_t elementId;
1238      bool openThisFrame;
1239      bool pointerScrollActive;
1240  } Clay__ScrollContainerDataInternal;
1241  
1242  CLAY__ARRAY_DEFINE(Clay__ScrollContainerDataInternal, Clay__ScrollContainerDataInternalArray)
1243  
1244  // Data representing the current internal state of a transition element.
1245  typedef struct Clay__TransitionDataInternal {
1246      Clay_TransitionData initialState;
1247      Clay_TransitionData currentState;
1248      Clay_TransitionData targetState;
1249      Clay_LayoutElement* elementThisFrame;
1250      Clay_Vector2 oldParentRelativePosition;
1251      uint32_t elementId;
1252      uint32_t parentId;
1253      uint32_t siblingIndex;
1254      float elapsedTime;
1255      Clay_TransitionState state;
1256      bool transitionOut;
1257      bool reparented;
1258      Clay_TransitionProperty activeProperties;
1259  } Clay__TransitionDataInternal;
1260  
1261  CLAY__ARRAY_DEFINE(Clay__TransitionDataInternal, Clay__TransitionDataInternalArray)
1262  
1263  typedef struct {
1264      bool collision;
1265      bool collapsed;
1266  } Clay__DebugElementData;
1267  
1268  CLAY__ARRAY_DEFINE(Clay__DebugElementData, Clay__DebugElementDataArray)
1269  
1270  typedef struct { // todo get this struct into a single cache line
1271      Clay_BoundingBox boundingBox;
1272      Clay_ElementId elementId;
1273      Clay_LayoutElement* layoutElement;
1274      void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerInfo, void *userData);
1275      void *hoverFunctionUserData;
1276      int32_t nextIndex;
1277      uint32_t generation;
1278      bool appearedThisFrame;
1279      Clay__DebugElementData *debugData;
1280  } Clay_LayoutElementHashMapItem;
1281  
1282  CLAY__ARRAY_DEFINE(Clay_LayoutElementHashMapItem, Clay__LayoutElementHashMapItemArray)
1283  
1284  typedef struct {
1285      int32_t startOffset;
1286      int32_t length;
1287      float width;
1288      int32_t next;
1289  } Clay__MeasuredWord;
1290  
1291  CLAY__ARRAY_DEFINE(Clay__MeasuredWord, Clay__MeasuredWordArray)
1292  
1293  typedef struct {
1294      Clay_Dimensions unwrappedDimensions;
1295      int32_t measuredWordsStartIndex;
1296      float minWidth;
1297      bool containsNewlines;
1298      // Hash map data
1299      uint32_t id;
1300      int32_t nextIndex;
1301      uint32_t generation;
1302  } Clay__MeasureTextCacheItem;
1303  
1304  CLAY__ARRAY_DEFINE(Clay__MeasureTextCacheItem, Clay__MeasureTextCacheItemArray)
1305  
1306  typedef struct {
1307      Clay_LayoutElement *layoutElement;
1308      Clay_Vector2 position;
1309      Clay_Vector2 nextChildOffset;
1310      bool parentMovedThisFramed; // Used to relativise transitions
1311  } Clay__LayoutElementTreeNode;
1312  
1313  CLAY__ARRAY_DEFINE(Clay__LayoutElementTreeNode, Clay__LayoutElementTreeNodeArray)
1314  
1315  typedef struct {
1316      int32_t layoutElementIndex;
1317      uint32_t parentId; // This can be zero in the case of the root layout tree
1318      uint32_t clipElementId; // This can be zero if there is no clip element
1319      int16_t zIndex;
1320      Clay_Vector2 pointerOffset; // Only used when scroll containers are managed externally
1321  } Clay__LayoutElementTreeRoot;
1322  
1323  CLAY__ARRAY_DEFINE(Clay__LayoutElementTreeRoot, Clay__LayoutElementTreeRootArray)
1324  
1325  struct Clay_Context {
1326      int32_t maxElementCount;
1327      int32_t maxMeasureTextCacheWordCount;
1328      int32_t exitingElementsLength;
1329      int32_t exitingElementsChildrenLength;
1330      bool warningsEnabled;
1331      bool rootResizedLastFrame;
1332      Clay_ErrorHandler errorHandler;
1333      Clay_BooleanWarnings booleanWarnings;
1334      Clay__WarningArray warnings;
1335  
1336      Clay_PointerData pointerInfo;
1337      Clay_Dimensions layoutDimensions;
1338      Clay_ElementId dynamicElementIndexBaseHash;
1339      uint32_t dynamicElementIndex;
1340      bool debugModeEnabled;
1341      bool disableCulling;
1342      bool externalScrollHandlingEnabled;
1343      uint32_t debugSelectedElementId;
1344      uint32_t generation;
1345      uintptr_t arenaResetOffset;
1346      void *measureTextUserData;
1347      void *queryScrollOffsetUserData;
1348      Clay_Arena internalArena;
1349      // Layout Elements / Render Commands
1350      Clay_LayoutElementArray layoutElements;
1351      Clay_RenderCommandArray renderCommands;
1352      Clay__int32_tArray openLayoutElementStack;
1353      Clay__int32_tArray layoutElementChildren;
1354      Clay__int32_tArray layoutElementChildrenBuffer;
1355      Clay__int32_tArray reusableElementIndexBuffer;
1356      Clay__int32_tArray layoutElementClipElementIds;
1357      // Misc Data Structures
1358      Clay__StringArray layoutElementIdStrings;
1359      Clay__WrappedTextLineArray wrappedTextLines;
1360      Clay__LayoutElementTreeNodeArray layoutElementTreeNodeArray1;
1361      Clay__LayoutElementTreeRootArray layoutElementTreeRoots;
1362      Clay__LayoutElementHashMapItemArray layoutElementsHashMapInternal;
1363      Clay__int32_tArray layoutElementsHashMap;
1364      Clay__MeasureTextCacheItemArray measureTextHashMapInternal;
1365      Clay__int32_tArray measureTextHashMapInternalFreeList;
1366      Clay__int32_tArray measureTextHashMap;
1367      Clay__MeasuredWordArray measuredWords;
1368      Clay__int32_tArray measuredWordsFreeList;
1369      Clay__int32_tArray openClipElementStack;
1370      Clay_ElementIdArray pointerOverIds;
1371      Clay__ScrollContainerDataInternalArray scrollContainerDatas;
1372      Clay__TransitionDataInternalArray transitionDatas;
1373      Clay__boolArray treeNodeVisited;
1374      Clay__charArray dynamicStringData;
1375      Clay__DebugElementDataArray debugElementData;
1376  };
1377  
1378  Clay_Context* Clay__Context_Allocate_Arena(Clay_Arena *arena) {
1379      size_t totalSizeBytes = sizeof(Clay_Context);
1380      if (totalSizeBytes > arena->capacity)
1381      {
1382          return NULL;
1383      }
1384      arena->nextAllocation += totalSizeBytes;
1385      return (Clay_Context*)(arena->memory);
1386  }
1387  
1388  Clay_String Clay__WriteStringToCharBuffer(Clay__charArray *buffer, Clay_String string) {
1389      for (int32_t i = 0; i < string.length; i++) {
1390          buffer->internalArray[buffer->length + i] = string.chars[i];
1391      }
1392      buffer->length += string.length;
1393      return CLAY__INIT(Clay_String) { .length = string.length, .chars = (const char *)(buffer->internalArray + buffer->length - string.length) };
1394  }
1395  
1396  #ifdef CLAY_WASM
1397      __attribute__((import_module("clay"), import_name("measureTextFunction"))) Clay_Dimensions Clay__MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData);
1398      __attribute__((import_module("clay"), import_name("queryScrollOffsetFunction"))) Clay_Vector2 Clay__QueryScrollOffset(uint32_t elementId, void *userData);
1399  #else
1400      Clay_Dimensions (*Clay__MeasureText)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData);
1401      Clay_Vector2 (*Clay__QueryScrollOffset)(uint32_t elementId, void *userData);
1402  #endif
1403  
1404  Clay_LayoutElement* Clay__GetOpenLayoutElement(void) {
1405      Clay_Context* context = Clay_GetCurrentContext();
1406      return Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 1));
1407  }
1408  
1409  Clay_LayoutElement* Clay__GetParentElement(void) {
1410      Clay_Context* context = Clay_GetCurrentContext();
1411      return Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2));
1412  }
1413  
1414  uint32_t Clay__GetParentElementId(void) {
1415      return Clay__GetParentElement()->id;
1416  }
1417  
1418  bool Clay__BorderHasAnyWidth(Clay_BorderElementConfig* borderConfig) {
1419      return borderConfig->width.betweenChildren > 0 || borderConfig->width.left > 0 || borderConfig->width.right > 0 || borderConfig->width.top > 0 || borderConfig->width.bottom > 0;
1420  }
1421  
1422  Clay_ElementId Clay__HashNumber(const uint32_t offset, const uint32_t seed) {
1423      uint32_t hash = seed;
1424      hash += (offset + 48);
1425      hash += (hash << 10);
1426      hash ^= (hash >> 6);
1427  
1428      hash += (hash << 3);
1429      hash ^= (hash >> 11);
1430      hash += (hash << 15);
1431      return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = seed, .stringId = CLAY__STRING_DEFAULT }; // Reserve the hash result of zero as "null id"
1432  }
1433  
1434  Clay_ElementId Clay__HashString(Clay_String key, const uint32_t seed) {
1435      uint32_t hash = seed;
1436  
1437      for (int32_t i = 0; i < key.length; i++) {
1438          hash += key.chars[i];
1439          hash += (hash << 10);
1440          hash ^= (hash >> 6);
1441      }
1442  
1443      hash += (hash << 3);
1444      hash ^= (hash >> 11);
1445      hash += (hash << 15);
1446      return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = 0, .baseId = hash + 1, .stringId = key }; // Reserve the hash result of zero as "null id"
1447  }
1448  
1449  Clay_ElementId Clay__HashStringWithOffset(Clay_String key, const uint32_t offset, const uint32_t seed) {
1450      uint32_t hash = 0;
1451      uint32_t base = seed;
1452  
1453      for (int32_t i = 0; i < key.length; i++) {
1454          base += key.chars[i];
1455          base += (base << 10);
1456          base ^= (base >> 6);
1457      }
1458      hash = base;
1459      hash += offset;
1460      hash += (hash << 10);
1461      hash ^= (hash >> 6);
1462  
1463      hash += (hash << 3);
1464      base += (base << 3);
1465      hash ^= (hash >> 11);
1466      base ^= (base >> 11);
1467      hash += (hash << 15);
1468      base += (base << 15);
1469      return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = base + 1, .stringId = key }; // Reserve the hash result of zero as "null id"
1470  }
1471  
1472  #if !defined(CLAY_DISABLE_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64))
1473  static inline __m128i Clay__SIMDRotateLeft(__m128i x, int r) {
1474      return _mm_or_si128(_mm_slli_epi64(x, r), _mm_srli_epi64(x, 64 - r));
1475  }
1476  
1477  static inline void Clay__SIMDARXMix(__m128i* a, __m128i* b) {
1478      *a = _mm_add_epi64(*a, *b);
1479      *b = _mm_xor_si128(Clay__SIMDRotateLeft(*b, 17), *a);
1480  }
1481  
1482  uint64_t Clay__HashData(const uint8_t* data, size_t length) {
1483      // Pinched these constants from the BLAKE implementation
1484      __m128i v0 = _mm_set1_epi64x(0x6a09e667f3bcc908ULL);
1485      __m128i v1 = _mm_set1_epi64x(0xbb67ae8584caa73bULL);
1486      __m128i v2 = _mm_set1_epi64x(0x3c6ef372fe94f82bULL);
1487      __m128i v3 = _mm_set1_epi64x(0xa54ff53a5f1d36f1ULL);
1488  
1489      uint8_t overflowBuffer[16] = { 0 };  // Temporary buffer for small inputs
1490  
1491      while (length > 0) {
1492          __m128i msg;
1493          if (length >= 16) {
1494              msg = _mm_loadu_si128((const __m128i*)data);
1495              data += 16;
1496              length -= 16;
1497          }
1498          else {
1499              for (size_t i = 0; i < length; i++) {
1500                  overflowBuffer[i] = data[i];
1501              }
1502              msg = _mm_loadu_si128((const __m128i*)overflowBuffer);
1503              length = 0;
1504          }
1505  
1506          v0 = _mm_xor_si128(v0, msg);
1507          Clay__SIMDARXMix(&v0, &v1);
1508          Clay__SIMDARXMix(&v2, &v3);
1509  
1510          v0 = _mm_add_epi64(v0, v2);
1511          v1 = _mm_add_epi64(v1, v3);
1512      }
1513  
1514      Clay__SIMDARXMix(&v0, &v1);
1515      Clay__SIMDARXMix(&v2, &v3);
1516      v0 = _mm_add_epi64(v0, v2);
1517      v1 = _mm_add_epi64(v1, v3);
1518      v0 = _mm_add_epi64(v0, v1);
1519  
1520      uint64_t result[2];
1521      _mm_storeu_si128((__m128i*)result, v0);
1522  
1523      return result[0] ^ result[1];
1524  }
1525  #elif !defined(CLAY_DISABLE_SIMD) && defined(__aarch64__)
1526  static inline void Clay__SIMDARXMix(uint64x2_t* a, uint64x2_t* b) {
1527      *a = vaddq_u64(*a, *b);
1528      *b = veorq_u64(vorrq_u64(vshlq_n_u64(*b, 17), vshrq_n_u64(*b, 64 - 17)), *a);
1529  }
1530  
1531  uint64_t Clay__HashData(const uint8_t* data, size_t length) {
1532      // Pinched these constants from the BLAKE implementation
1533      uint64x2_t v0 = vdupq_n_u64(0x6a09e667f3bcc908ULL);
1534      uint64x2_t v1 = vdupq_n_u64(0xbb67ae8584caa73bULL);
1535      uint64x2_t v2 = vdupq_n_u64(0x3c6ef372fe94f82bULL);
1536      uint64x2_t v3 = vdupq_n_u64(0xa54ff53a5f1d36f1ULL);
1537  
1538      uint8_t overflowBuffer[8] = { 0 };
1539  
1540      while (length > 0) {
1541          uint64x2_t msg;
1542          if (length > 16) {
1543              msg = vld1q_u64((const uint64_t*)data);
1544              data += 16;
1545              length -= 16;
1546          }
1547          else if (length > 8) {
1548              msg = vcombine_u64(vld1_u64((const uint64_t*)data), vdup_n_u64(0));
1549              data += 8;
1550              length -= 8;
1551          }
1552          else {
1553              for (size_t i = 0; i < length; i++) {
1554                  overflowBuffer[i] = data[i];
1555              }
1556              uint8x8_t lower = vld1_u8(overflowBuffer);
1557              msg = vreinterpretq_u64_u8(vcombine_u8(lower, vdup_n_u8(0)));
1558              length = 0;
1559          }
1560          v0 = veorq_u64(v0, msg);
1561          Clay__SIMDARXMix(&v0, &v1);
1562          Clay__SIMDARXMix(&v2, &v3);
1563  
1564          v0 = vaddq_u64(v0, v2);
1565          v1 = vaddq_u64(v1, v3);
1566      }
1567  
1568      Clay__SIMDARXMix(&v0, &v1);
1569      Clay__SIMDARXMix(&v2, &v3);
1570      v0 = vaddq_u64(v0, v2);
1571      v1 = vaddq_u64(v1, v3);
1572      v0 = vaddq_u64(v0, v1);
1573  
1574      uint64_t result[2];
1575      vst1q_u64(result, v0);
1576  
1577      return result[0] ^ result[1];
1578  }
1579  #else
1580  uint64_t Clay__HashData(const uint8_t* data, size_t length) {
1581      uint64_t hash = 0;
1582  
1583      for (size_t i = 0; i < length; i++) {
1584          hash += data[i];
1585          hash += (hash << 10);
1586          hash ^= (hash >> 6);
1587      }
1588      return hash;
1589  }
1590  #endif
1591  
1592  uint32_t Clay__HashStringContentsWithConfig(Clay_String *text, Clay_TextElementConfig *config) {
1593      uint32_t hash = 0;
1594      if (text->isStaticallyAllocated) {
1595          hash += (uintptr_t)text->chars;
1596          hash += (hash << 10);
1597          hash ^= (hash >> 6);
1598          hash += text->length;
1599          hash += (hash << 10);
1600          hash ^= (hash >> 6);
1601      } else {
1602          hash = Clay__HashData((const uint8_t *)text->chars, text->length) % UINT32_MAX;
1603      }
1604  
1605      hash += config->fontId;
1606      hash += (hash << 10);
1607      hash ^= (hash >> 6);
1608  
1609      hash += config->fontSize;
1610      hash += (hash << 10);
1611      hash ^= (hash >> 6);
1612  
1613      hash += config->letterSpacing;
1614      hash += (hash << 10);
1615      hash ^= (hash >> 6);
1616  
1617      hash += (hash << 3);
1618      hash ^= (hash >> 11);
1619      hash += (hash << 15);
1620      return hash + 1; // Reserve the hash result of zero as "null id"
1621  }
1622  
1623  Clay__MeasuredWord *Clay__AddMeasuredWord(Clay__MeasuredWord word, Clay__MeasuredWord *previousWord) {
1624      Clay_Context* context = Clay_GetCurrentContext();
1625      if (context->measuredWordsFreeList.length > 0) {
1626          uint32_t newItemIndex = Clay__int32_tArray_GetValue(&context->measuredWordsFreeList, (int)context->measuredWordsFreeList.length - 1);
1627          context->measuredWordsFreeList.length--;
1628          Clay__MeasuredWordArray_Set(&context->measuredWords, (int)newItemIndex, word);
1629          previousWord->next = (int32_t)newItemIndex;
1630          return Clay__MeasuredWordArray_Get(&context->measuredWords, (int)newItemIndex);
1631      } else {
1632          previousWord->next = (int32_t)context->measuredWords.length;
1633          return Clay__MeasuredWordArray_Add(&context->measuredWords, word);
1634      }
1635  }
1636  
1637  Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_TextElementConfig *config) {
1638      Clay_Context* context = Clay_GetCurrentContext();
1639      #ifndef CLAY_WASM
1640      if (!Clay__MeasureText) {
1641          if (!context->booleanWarnings.textMeasurementFunctionNotSet) {
1642              context->booleanWarnings.textMeasurementFunctionNotSet = true;
1643              context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
1644                      .errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED,
1645                      .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."),
1646                      .userData = context->errorHandler.userData });
1647          }
1648          return &Clay__MeasureTextCacheItem_DEFAULT;
1649      }
1650      #endif
1651      uint32_t id = Clay__HashStringContentsWithConfig(text, config);
1652      uint32_t hashBucket = id % (context->maxMeasureTextCacheWordCount / 32);
1653      int32_t elementIndexPrevious = 0;
1654      int32_t elementIndex = context->measureTextHashMap.internalArray[hashBucket];
1655      while (elementIndex != 0) {
1656          Clay__MeasureTextCacheItem *hashEntry = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndex);
1657          if (hashEntry->id == id) {
1658              hashEntry->generation = context->generation;
1659              return hashEntry;
1660          }
1661          // This element hasn't been seen in a few frames, delete the hash map item
1662          if (context->generation - hashEntry->generation > 2) {
1663              // Add all the measured words that were included in this measurement to the freelist
1664              int32_t nextWordIndex = hashEntry->measuredWordsStartIndex;
1665              while (nextWordIndex != -1) {
1666                  Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&context->measuredWords, nextWordIndex);
1667                  Clay__int32_tArray_Add(&context->measuredWordsFreeList, nextWordIndex);
1668                  nextWordIndex = measuredWord->next;
1669              }
1670  
1671              int32_t nextIndex = hashEntry->nextIndex;
1672              Clay__MeasureTextCacheItemArray_Set(&context->measureTextHashMapInternal, elementIndex, CLAY__INIT(Clay__MeasureTextCacheItem) { .measuredWordsStartIndex = -1 });
1673              Clay__int32_tArray_Add(&context->measureTextHashMapInternalFreeList, elementIndex);
1674              if (elementIndexPrevious == 0) {
1675                  context->measureTextHashMap.internalArray[hashBucket] = nextIndex;
1676              } else {
1677                  Clay__MeasureTextCacheItem *previousHashEntry = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndexPrevious);
1678                  previousHashEntry->nextIndex = nextIndex;
1679              }
1680              elementIndex = nextIndex;
1681          } else {
1682              elementIndexPrevious = elementIndex;
1683              elementIndex = hashEntry->nextIndex;
1684          }
1685      }
1686  
1687      int32_t newItemIndex = 0;
1688      Clay__MeasureTextCacheItem newCacheItem = { .measuredWordsStartIndex = -1, .id = id, .generation = context->generation };
1689      Clay__MeasureTextCacheItem *measured = NULL;
1690      if (context->measureTextHashMapInternalFreeList.length > 0) {
1691          newItemIndex = Clay__int32_tArray_GetValue(&context->measureTextHashMapInternalFreeList, context->measureTextHashMapInternalFreeList.length - 1);
1692          context->measureTextHashMapInternalFreeList.length--;
1693          Clay__MeasureTextCacheItemArray_Set(&context->measureTextHashMapInternal, newItemIndex, newCacheItem);
1694          measured = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, newItemIndex);
1695      } else {
1696          if (context->measureTextHashMapInternal.length == context->measureTextHashMapInternal.capacity - 1) {
1697              if (!context->booleanWarnings.maxTextMeasureCacheExceeded) {
1698                  context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
1699                          .errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
1700                          .errorText = CLAY_STRING("Clay ran out of capacity while attempting to measure text elements. Try using Clay_SetMaxElementCount() with a higher value."),
1701                          .userData = context->errorHandler.userData });
1702                  context->booleanWarnings.maxTextMeasureCacheExceeded = true;
1703              }
1704              return &Clay__MeasureTextCacheItem_DEFAULT;
1705          }
1706          measured = Clay__MeasureTextCacheItemArray_Add(&context->measureTextHashMapInternal, newCacheItem);
1707          newItemIndex = context->measureTextHashMapInternal.length - 1;
1708      }
1709  
1710      int32_t start = 0;
1711      int32_t end = 0;
1712      float lineWidth = 0;
1713      float measuredWidth = 0;
1714      float measuredHeight = 0;
1715      float spaceWidth = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = 1, .chars = CLAY__SPACECHAR.chars, .baseChars = CLAY__SPACECHAR.chars }, config, context->measureTextUserData).width;
1716      Clay__MeasuredWord tempWord = { .next = -1 };
1717      Clay__MeasuredWord *previousWord = &tempWord;
1718      while (end < text->length) {
1719          if (context->measuredWords.length == context->measuredWords.capacity - 1) {
1720              if (!context->booleanWarnings.maxTextMeasureCacheExceeded) {
1721                  context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
1722                      .errorType = CLAY_ERROR_TYPE_TEXT_MEASUREMENT_CAPACITY_EXCEEDED,
1723                      .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)."),
1724                      .userData = context->errorHandler.userData });
1725                  context->booleanWarnings.maxTextMeasureCacheExceeded = true;
1726              }
1727              return &Clay__MeasureTextCacheItem_DEFAULT;
1728          }
1729          char current = text->chars[end];
1730          if (current == ' ' || current == '\n') {
1731              int32_t length = end - start;
1732              Clay_Dimensions dimensions = CLAY__DEFAULT_STRUCT;
1733              if (length > 0) {
1734                  dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) {.length = length, .chars = &text->chars[start], .baseChars = text->chars}, config, context->measureTextUserData);
1735              }
1736              measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
1737              measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
1738              if (current == ' ') {
1739                  dimensions.width += spaceWidth;
1740                  previousWord = Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = length + 1, .width = dimensions.width, .next = -1 }, previousWord);
1741                  lineWidth += dimensions.width;
1742              }
1743              if (current == '\n') {
1744                  if (length > 0) {
1745                      previousWord = Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = length, .width = dimensions.width, .next = -1 }, previousWord);
1746                  }
1747                  previousWord = Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = end + 1, .length = 0, .width = 0, .next = -1 }, previousWord);
1748                  lineWidth += dimensions.width;
1749                  measuredWidth = CLAY__MAX(lineWidth, measuredWidth);
1750                  measured->containsNewlines = true;
1751                  lineWidth = 0;
1752              }
1753              start = end + 1;
1754          }
1755          end++;
1756      }
1757      if (end - start > 0) {
1758          Clay_Dimensions dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = end - start, .chars = &text->chars[start], .baseChars = text->chars }, config, context->measureTextUserData);
1759          Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = end - start, .width = dimensions.width, .next = -1 }, previousWord);
1760          lineWidth += dimensions.width;
1761          measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
1762          measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
1763      }
1764      measuredWidth = CLAY__MAX(lineWidth, measuredWidth) - config->letterSpacing;
1765  
1766      measured->measuredWordsStartIndex = tempWord.next;
1767      measured->unwrappedDimensions.width = measuredWidth;
1768      measured->unwrappedDimensions.height = measuredHeight;
1769  
1770      if (elementIndexPrevious != 0) {
1771          Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, elementIndexPrevious)->nextIndex = newItemIndex;
1772      } else {
1773          context->measureTextHashMap.internalArray[hashBucket] = newItemIndex;
1774      }
1775      return measured;
1776  }
1777  
1778  bool Clay__PointIsInsideRect(Clay_Vector2 point, Clay_BoundingBox rect) {
1779      return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height;
1780  }
1781  
1782  Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Clay_LayoutElement* layoutElement) {
1783      Clay_Context* context = Clay_GetCurrentContext();
1784      if (context->layoutElementsHashMapInternal.length == context->layoutElementsHashMapInternal.capacity - 1) {
1785          return NULL;
1786      }
1787      Clay_LayoutElementHashMapItem item = { .elementId = elementId, .layoutElement = layoutElement, .nextIndex = -1, .generation = context->generation + 1, .appearedThisFrame = true };
1788      uint32_t hashBucket = elementId.id % context->layoutElementsHashMap.capacity;
1789      int32_t hashItemPrevious = -1;
1790      int32_t hashItemIndex = context->layoutElementsHashMap.internalArray[hashBucket];
1791      while (hashItemIndex != -1) { // Just replace collision, not a big deal - leave it up to the end user
1792          Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemIndex);
1793          if (hashItem->elementId.id == elementId.id) { // Collision - resolve based on generation
1794              item.nextIndex = hashItem->nextIndex;
1795              if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element
1796                  hashItem->appearedThisFrame = hashItem->generation < context->generation;
1797                  hashItem->elementId = elementId; // Make sure to copy this across. If the stringId reference has changed, we should update the hash item to use the new one.
1798                  hashItem->generation = context->generation + 1;
1799                  hashItem->layoutElement = layoutElement;
1800                  hashItem->debugData->collision = false;
1801                  hashItem->onHoverFunction = NULL;
1802                  hashItem->hoverFunctionUserData = 0;
1803              } else { // Multiple collisions this frame - two elements have the same ID
1804                  context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
1805                      .errorType = CLAY_ERROR_TYPE_DUPLICATE_ID,
1806                      .errorText = CLAY_STRING("An element with this ID was already previously declared during this layout."),
1807                      .userData = context->errorHandler.userData });
1808                  if (context->debugModeEnabled) {
1809                      hashItem->debugData->collision = true;
1810                  }
1811              }
1812              return hashItem;
1813          }
1814          hashItemPrevious = hashItemIndex;
1815          hashItemIndex = hashItem->nextIndex;
1816      }
1817      Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Add(&context->layoutElementsHashMapInternal, item);
1818      hashItem->debugData = Clay__DebugElementDataArray_Add(&context->debugElementData, CLAY__INIT(Clay__DebugElementData) CLAY__DEFAULT_STRUCT);
1819      if (hashItemPrevious != -1) {
1820          Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, hashItemPrevious)->nextIndex = (int32_t)context->layoutElementsHashMapInternal.length - 1;
1821      } else {
1822          context->layoutElementsHashMap.internalArray[hashBucket] = (int32_t)context->layoutElementsHashMapInternal.length - 1;
1823      }
1824      return hashItem;
1825  }
1826  
1827  Clay_LayoutElementHashMapItem *Clay__GetHashMapItem(uint32_t id) {
1828      Clay_Context* context = Clay_GetCurrentContext();
1829      uint32_t hashBucket = id % context->layoutElementsHashMap.capacity;
1830      int32_t elementIndex = context->layoutElementsHashMap.internalArray[hashBucket];
1831      while (elementIndex != -1) {
1832          Clay_LayoutElementHashMapItem *hashEntry = Clay__LayoutElementHashMapItemArray_Get(&context->layoutElementsHashMapInternal, elementIndex);
1833          if (hashEntry->elementId.id == id) {
1834              return hashEntry;
1835          }
1836          elementIndex = hashEntry->nextIndex;
1837      }
1838      return &Clay_LayoutElementHashMapItem_DEFAULT;
1839  }
1840  
1841  void Clay__UpdateAspectRatioBox(Clay_LayoutElement *layoutElement) {
1842      if (layoutElement->config.aspectRatio.aspectRatio != 0) {
1843          if (layoutElement->dimensions.width == 0 && layoutElement->dimensions.height != 0) {
1844              layoutElement->dimensions.width = layoutElement->dimensions.height * layoutElement->config.aspectRatio.aspectRatio;
1845          } else if (layoutElement->dimensions.width != 0 && layoutElement->dimensions.height == 0) {
1846              layoutElement->dimensions.height = layoutElement->dimensions.width * (1 / layoutElement->config.aspectRatio.aspectRatio);
1847          }
1848      }
1849  }
1850  
1851  void Clay__CloseElement(void) {
1852      Clay_Context* context = Clay_GetCurrentContext();
1853      if (context->booleanWarnings.maxElementsExceeded) {
1854          return;
1855      }
1856      Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
1857      Clay_LayoutConfig *layoutConfig = &openLayoutElement->config.layout;
1858      bool elementHasClipHorizontal = openLayoutElement->config.clip.horizontal;
1859      bool elementHasClipVertical = openLayoutElement->config.clip.vertical;
1860      if (elementHasClipHorizontal || elementHasClipVertical || openLayoutElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
1861          context->openClipElementStack.length--;
1862      }
1863  
1864      float leftRightPadding = (float)(layoutConfig->padding.left + layoutConfig->padding.right);
1865      float topBottomPadding = (float)(layoutConfig->padding.top + layoutConfig->padding.bottom);
1866  
1867      // Attach children to the current open element
1868      openLayoutElement->children.elements = &context->layoutElementChildren.internalArray[context->layoutElementChildren.length];
1869      if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
1870          openLayoutElement->dimensions.width = leftRightPadding;
1871          openLayoutElement->minDimensions.width = leftRightPadding;
1872          for (int32_t i = 0; i < openLayoutElement->children.length; i++) {
1873              int32_t childIndex = Clay__int32_tArray_GetValue(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->children.length + i);
1874              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex);
1875              openLayoutElement->dimensions.width += child->dimensions.width;
1876              openLayoutElement->dimensions.height = CLAY__MAX(openLayoutElement->dimensions.height, child->dimensions.height + topBottomPadding);
1877              // Minimum size of child elements doesn't matter to clip containers as they can shrink and hide their contents
1878              if (!elementHasClipHorizontal) {
1879                  openLayoutElement->minDimensions.width += child->minDimensions.width;
1880              }
1881              if (!elementHasClipVertical) {
1882                  openLayoutElement->minDimensions.height = CLAY__MAX(openLayoutElement->minDimensions.height, child->minDimensions.height + topBottomPadding);
1883              }
1884              Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
1885          }
1886          float childGap = (float)(CLAY__MAX(openLayoutElement->children.length - 1, 0) * layoutConfig->childGap);
1887          openLayoutElement->dimensions.width += childGap;
1888          if (!elementHasClipHorizontal) {
1889              openLayoutElement->minDimensions.width += childGap;
1890          }
1891      }
1892      else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) {
1893          openLayoutElement->dimensions.height = topBottomPadding;
1894          openLayoutElement->minDimensions.height = topBottomPadding;
1895          for (int32_t i = 0; i < openLayoutElement->children.length; i++) {
1896              int32_t childIndex = Clay__int32_tArray_GetValue(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->children.length + i);
1897              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex);
1898              openLayoutElement->dimensions.height += child->dimensions.height;
1899              openLayoutElement->dimensions.width = CLAY__MAX(openLayoutElement->dimensions.width, child->dimensions.width + leftRightPadding);
1900              // Minimum size of child elements doesn't matter to clip containers as they can shrink and hide their contents
1901              if (!elementHasClipVertical) {
1902                  openLayoutElement->minDimensions.height += child->minDimensions.height;
1903              }
1904              if (!elementHasClipHorizontal) {
1905                  openLayoutElement->minDimensions.width = CLAY__MAX(openLayoutElement->minDimensions.width, child->minDimensions.width + leftRightPadding);
1906              }
1907              Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
1908          }
1909          float childGap = (float)(CLAY__MAX(openLayoutElement->children.length - 1, 0) * layoutConfig->childGap);
1910          openLayoutElement->dimensions.height += childGap;
1911          if (!elementHasClipVertical) {
1912              openLayoutElement->minDimensions.height += childGap;
1913          }
1914      }
1915  
1916      context->layoutElementChildrenBuffer.length -= openLayoutElement->children.length;
1917  
1918      // Clamp element min and max width to the values configured in the layout
1919      if (layoutConfig->sizing.width.type != CLAY__SIZING_TYPE_PERCENT) {
1920          if (layoutConfig->sizing.width.size.minMax.max <= 0) { // Set the max size if the user didn't specify, makes calculations easier
1921              layoutConfig->sizing.width.size.minMax.max = CLAY__MAXFLOAT;
1922          }
1923          openLayoutElement->dimensions.width = CLAY__MIN(CLAY__MAX(openLayoutElement->dimensions.width, layoutConfig->sizing.width.size.minMax.min), layoutConfig->sizing.width.size.minMax.max);
1924          openLayoutElement->minDimensions.width = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.width, layoutConfig->sizing.width.size.minMax.min), layoutConfig->sizing.width.size.minMax.max);
1925      } else {
1926          openLayoutElement->dimensions.width = 0;
1927      }
1928  
1929      // Clamp element min and max height to the values configured in the layout
1930      if (layoutConfig->sizing.height.type != CLAY__SIZING_TYPE_PERCENT) {
1931          if (layoutConfig->sizing.height.size.minMax.max <= 0) { // Set the max size if the user didn't specify, makes calculations easier
1932              layoutConfig->sizing.height.size.minMax.max = CLAY__MAXFLOAT;
1933          }
1934          openLayoutElement->dimensions.height = CLAY__MIN(CLAY__MAX(openLayoutElement->dimensions.height, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max);
1935          openLayoutElement->minDimensions.height = CLAY__MIN(CLAY__MAX(openLayoutElement->minDimensions.height, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max);
1936      } else {
1937          openLayoutElement->dimensions.height = 0;
1938      }
1939  
1940      Clay__UpdateAspectRatioBox(openLayoutElement);
1941  
1942      bool elementIsFloating = openLayoutElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE;
1943  
1944      // Close the currently open element
1945      int32_t closingElementIndex = Clay__int32_tArray_RemoveSwapback(&context->openLayoutElementStack, (int)context->openLayoutElementStack.length - 1);
1946  
1947      // Get the currently open parent
1948      openLayoutElement = Clay__GetOpenLayoutElement();
1949  
1950      if (context->openLayoutElementStack.length > 1) {
1951          if(elementIsFloating) {
1952              openLayoutElement->floatingChildrenCount++;
1953              return;
1954          }
1955          openLayoutElement->children.length++;
1956          Clay__int32_tArray_Add(&context->layoutElementChildrenBuffer, closingElementIndex);
1957      }
1958  }
1959  
1960  bool Clay__MemCmp(const char *s1, const char *s2, int32_t length);
1961  #if !defined(CLAY_DISABLE_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64))
1962      bool Clay__MemCmp(const char *s1, const char *s2, int32_t length) {
1963          while (length >= 16) {
1964              __m128i v1 = _mm_loadu_si128((const __m128i *)s1);
1965              __m128i v2 = _mm_loadu_si128((const __m128i *)s2);
1966  
1967              if (_mm_movemask_epi8(_mm_cmpeq_epi8(v1, v2)) != 0xFFFF) { // If any byte differs
1968                  return false;
1969              }
1970  
1971              s1 += 16;
1972              s2 += 16;
1973              length -= 16;
1974          }
1975  
1976          // Handle remaining bytes
1977          while (length--) {
1978              if (*s1 != *s2) {
1979                  return false;
1980              }
1981              s1++;
1982              s2++;
1983          }
1984  
1985          return true;
1986      }
1987  #elif !defined(CLAY_DISABLE_SIMD) && defined(__aarch64__)
1988      bool Clay__MemCmp(const char *s1, const char *s2, int32_t length) {
1989          while (length >= 16) {
1990              uint8x16_t v1 = vld1q_u8((const uint8_t *)s1);
1991              uint8x16_t v2 = vld1q_u8((const uint8_t *)s2);
1992  
1993              // Compare vectors
1994              if (vminvq_u32(vreinterpretq_u32_u8(vceqq_u8(v1, v2))) != 0xFFFFFFFF) { // If there's a difference
1995                  return false;
1996              }
1997  
1998              s1 += 16;
1999              s2 += 16;
2000              length -= 16;
2001          }
2002  
2003          // Handle remaining bytes
2004          while (length--) {
2005              if (*s1 != *s2) {
2006                  return false;
2007              }
2008              s1++;
2009              s2++;
2010          }
2011  
2012          return true;
2013      }
2014  #else
2015      bool Clay__MemCmp(const char *s1, const char *s2, int32_t length) {
2016          for (int32_t i = 0; i < length; i++) {
2017              if (s1[i] != s2[i]) {
2018                  return false;
2019              }
2020          }
2021          return true;
2022      }
2023  #endif
2024  
2025  void Clay__OpenElement(void) {
2026      Clay_Context* context = Clay_GetCurrentContext();
2027      if (context->layoutElements.length == context->layoutElements.capacity - 1 || context->booleanWarnings.maxElementsExceeded) {
2028          context->booleanWarnings.maxElementsExceeded = true;
2029          return;
2030      }
2031      Clay_LayoutElement layoutElement = CLAY__DEFAULT_STRUCT;
2032      Clay_LayoutElement* openLayoutElement = Clay_LayoutElementArray_Add(&context->layoutElements, layoutElement);
2033      Clay__int32_tArray_Add(&context->openLayoutElementStack, context->layoutElements.length - 1);
2034      // Generate an ID
2035      Clay_LayoutElement *parentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2));
2036      uint32_t offset = parentElement->children.length + parentElement->floatingChildrenCount;
2037      Clay_ElementId elementId = Clay__HashNumber(offset, parentElement->id);
2038      openLayoutElement->id = elementId.id;
2039      Clay__AddHashMapItem(elementId, openLayoutElement);
2040      Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId);
2041      if (context->openClipElementStack.length > 0) {
2042          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, Clay__int32_tArray_GetValue(&context->openClipElementStack, (int)context->openClipElementStack.length - 1));
2043      } else {
2044          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, 0);
2045      }
2046  }
2047  
2048  void Clay__OpenElementWithId(Clay_ElementId elementId) {
2049      Clay_Context* context = Clay_GetCurrentContext();
2050      if (context->layoutElements.length == context->layoutElements.capacity - 1 || context->booleanWarnings.maxElementsExceeded) {
2051          context->booleanWarnings.maxElementsExceeded = true;
2052          return;
2053      }
2054      Clay_LayoutElement layoutElement = CLAY__DEFAULT_STRUCT;
2055      layoutElement.id = elementId.id;
2056      Clay_LayoutElement * openLayoutElement = Clay_LayoutElementArray_Add(&context->layoutElements, layoutElement);
2057      Clay__int32_tArray_Add(&context->openLayoutElementStack, context->layoutElements.length - 1);
2058      Clay__AddHashMapItem(elementId, openLayoutElement);
2059      Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId);
2060      if (context->openClipElementStack.length > 0) {
2061          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, Clay__int32_tArray_GetValue(&context->openClipElementStack, (int)context->openClipElementStack.length - 1));
2062      } else {
2063          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, 0);
2064      }
2065  }
2066  
2067  void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig textConfig) {
2068      Clay_Context* context = Clay_GetCurrentContext();
2069      if (context->layoutElements.length == context->layoutElements.capacity - 1 || context->booleanWarnings.maxElementsExceeded) {
2070          context->booleanWarnings.maxElementsExceeded = true;
2071          return;
2072      }
2073      Clay_LayoutElement *parentElement = Clay__GetOpenLayoutElement();
2074  
2075      Clay_LayoutElement layoutElement = { .textConfig = textConfig, .isTextElement = true };
2076      Clay_LayoutElement *textElement = Clay_LayoutElementArray_Add(&context->layoutElements, layoutElement);
2077      if (context->openClipElementStack.length > 0) {
2078          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, Clay__int32_tArray_GetValue(&context->openClipElementStack, (int)context->openClipElementStack.length - 1));
2079      } else {
2080          Clay__int32_tArray_Set(&context->layoutElementClipElementIds, context->layoutElements.length - 1, 0);
2081      }
2082  
2083      Clay__int32_tArray_Add(&context->layoutElementChildrenBuffer, context->layoutElements.length - 1);
2084      Clay__MeasureTextCacheItem *textMeasured = Clay__MeasureTextCached(&text, &textConfig);
2085      Clay_ElementId elementId = Clay__HashNumber(parentElement->children.length + parentElement->floatingChildrenCount, parentElement->id);
2086      textElement->id = elementId.id;
2087      Clay__AddHashMapItem(elementId, textElement);
2088      Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId);
2089      Clay_Dimensions textDimensions = { .width = textMeasured->unwrappedDimensions.width, .height = textConfig.lineHeight > 0 ? (float)textConfig.lineHeight : textMeasured->unwrappedDimensions.height };
2090      textElement->dimensions = textDimensions;
2091      textElement->minDimensions = CLAY__INIT(Clay_Dimensions) { .width = textMeasured->minWidth, .height = textDimensions.height };
2092      textElement->textElementData = CLAY__INIT(Clay__TextElementData) { .text = text, .preferredDimensions = textMeasured->unwrappedDimensions };
2093      parentElement->children.length++;
2094  }
2095  
2096  void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *declaration) {
2097      Clay_Context* context = Clay_GetCurrentContext();
2098      Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
2099      openLayoutElement->config = *declaration;
2100      if ((declaration->layout.sizing.width.type == CLAY__SIZING_TYPE_PERCENT && declaration->layout.sizing.width.size.percent > 1) || (declaration->layout.sizing.height.type == CLAY__SIZING_TYPE_PERCENT && declaration->layout.sizing.height.size.percent > 1)) {
2101          context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
2102                  .errorType = CLAY_ERROR_TYPE_PERCENTAGE_OVER_1,
2103                  .errorText = CLAY_STRING("An element was configured with CLAY_SIZING_PERCENT, but the provided percentage value was over 1.0. Clay expects a value between 0 and 1, i.e. 20% is 0.2."),
2104                  .userData = context->errorHandler.userData });
2105      }
2106  
2107      if (declaration->floating.attachTo != CLAY_ATTACH_TO_NONE) {
2108          Clay_FloatingElementConfig* floatingConfig = &openLayoutElement->config.floating;
2109          // This looks dodgy but because of the auto generated root element the depth of the tree will always be at least 2 here
2110          Clay_LayoutElement *hierarchicalParent = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 2));
2111          if (hierarchicalParent) {
2112              uint32_t clipElementId = 0;
2113              if (declaration->floating.attachTo == CLAY_ATTACH_TO_PARENT) {
2114                  // Attach to the element's direct hierarchical parent
2115                  floatingConfig->parentId = hierarchicalParent->id;
2116                  if (context->openClipElementStack.length > 0) {
2117                      clipElementId = Clay__int32_tArray_GetValue(&context->openClipElementStack, (int)context->openClipElementStack.length - 1);
2118                  }
2119              } else if (declaration->floating.attachTo == CLAY_ATTACH_TO_ELEMENT_WITH_ID) {
2120                  Clay_LayoutElementHashMapItem *parentItem = Clay__GetHashMapItem(floatingConfig->parentId);
2121                  if (parentItem == &Clay_LayoutElementHashMapItem_DEFAULT) {
2122                      context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
2123                              .errorType = CLAY_ERROR_TYPE_FLOATING_CONTAINER_PARENT_NOT_FOUND,
2124                              .errorText = CLAY_STRING("A floating element was declared with a parentId, but no element with that ID was found."),
2125                              .userData = context->errorHandler.userData });
2126                  } else {
2127                      clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, (int32_t)(parentItem->layoutElement - context->layoutElements.internalArray));
2128                  }
2129              } else if (declaration->floating.attachTo == CLAY_ATTACH_TO_ROOT) {
2130                  floatingConfig->parentId = Clay__HashString(CLAY_STRING("Clay__RootContainer"), 0).id;
2131              }
2132              if (declaration->floating.clipTo == CLAY_CLIP_TO_NONE) {
2133                  clipElementId = 0;
2134              }
2135              int32_t currentElementIndex = Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 1);
2136              Clay__int32_tArray_Set(&context->layoutElementClipElementIds, currentElementIndex, clipElementId);
2137              Clay__int32_tArray_Add(&context->openClipElementStack, clipElementId);
2138              Clay__LayoutElementTreeRootArray_Add(&context->layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) {
2139                  .layoutElementIndex = Clay__int32_tArray_GetValue(&context->openLayoutElementStack, context->openLayoutElementStack.length - 1),
2140                  .parentId = floatingConfig->parentId,
2141                  .clipElementId = clipElementId,
2142                  .zIndex = floatingConfig->zIndex,
2143              });
2144          }
2145      }
2146  
2147      if (declaration->clip.horizontal || declaration->clip.vertical) {
2148          Clay__int32_tArray_Add(&context->openClipElementStack, (int)openLayoutElement->id);
2149          // Retrieve or create cached data to track scroll position across frames
2150          Clay__ScrollContainerDataInternal *scrollOffset = CLAY__NULL;
2151          for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) {
2152              Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
2153              if (openLayoutElement->id == mapping->elementId) {
2154                  scrollOffset = mapping;
2155                  scrollOffset->layoutElement = openLayoutElement;
2156                  scrollOffset->openThisFrame = true;
2157              }
2158          }
2159          if (!scrollOffset) {
2160              scrollOffset = Clay__ScrollContainerDataInternalArray_Add(&context->scrollContainerDatas, CLAY__INIT(Clay__ScrollContainerDataInternal){.layoutElement = openLayoutElement, .scrollOrigin = {-1,-1}, .elementId = openLayoutElement->id, .openThisFrame = true});
2161          }
2162          if (context->externalScrollHandlingEnabled) {
2163              scrollOffset->scrollPosition = Clay__QueryScrollOffset(scrollOffset->elementId, context->queryScrollOffsetUserData);
2164          }
2165      }
2166      // Setup data to track transitions across frames
2167      if (declaration->transition.handler) {
2168          Clay__TransitionDataInternal *transitionData = CLAY__NULL;
2169          Clay_LayoutElement* parentElement = Clay__GetParentElement();
2170          for (int32_t i = 0; i < context->transitionDatas.length; i++) {
2171              Clay__TransitionDataInternal *existingData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i);
2172              if (openLayoutElement->id == existingData->elementId) {
2173                  if (existingData->state == CLAY_TRANSITION_STATE_EXITING) {
2174                      existingData->state = CLAY_TRANSITION_STATE_IDLE;
2175                      Clay_LayoutElementHashMapItem* hashMapItem = Clay__GetHashMapItem(openLayoutElement->id);
2176                      hashMapItem->appearedThisFrame = false;
2177                  }
2178                  transitionData = existingData;
2179                  transitionData->elementThisFrame = openLayoutElement;
2180                  if (transitionData->parentId != parentElement->id) {
2181                      transitionData->reparented = true;
2182                  }
2183                  transitionData->parentId = parentElement->id;
2184                  transitionData->siblingIndex = parentElement->children.length;
2185                  transitionData->transitionOut = !!declaration->transition.exit.setFinalState;
2186              }
2187          }
2188          if (!transitionData) {
2189              transitionData = Clay__TransitionDataInternalArray_Add(&context->transitionDatas, CLAY__INIT(Clay__TransitionDataInternal){
2190                  .elementThisFrame = openLayoutElement,
2191                  .elementId = openLayoutElement->id,
2192                  .parentId = parentElement->id,
2193                  .siblingIndex = parentElement->children.length,
2194                  .transitionOut = !!declaration->transition.exit.setFinalState
2195              });
2196          }
2197      }
2198  }
2199  
2200  void Clay__ConfigureOpenElement(const Clay_ElementDeclaration declaration) {
2201      Clay__ConfigureOpenElementPtr(&declaration);
2202  }
2203  
2204  void Clay__InitializeEphemeralMemory(Clay_Context* context) {
2205      int32_t maxElementCount = context->maxElementCount;
2206      // Ephemeral Memory - reset every frame
2207      Clay_Arena *arena = &context->internalArena;
2208      arena->nextAllocation = context->arenaResetOffset;
2209  
2210      context->layoutElementChildrenBuffer = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2211      context->layoutElements = Clay_LayoutElementArray_Allocate_Arena(maxElementCount, arena);
2212      context->warnings = Clay__WarningArray_Allocate_Arena(100, arena);
2213  
2214      context->layoutElementIdStrings = Clay__StringArray_Allocate_Arena(maxElementCount, arena);
2215      context->wrappedTextLines = Clay__WrappedTextLineArray_Allocate_Arena(maxElementCount, arena);
2216      context->layoutElementTreeNodeArray1 = Clay__LayoutElementTreeNodeArray_Allocate_Arena(maxElementCount, arena);
2217      context->layoutElementTreeRoots = Clay__LayoutElementTreeRootArray_Allocate_Arena(maxElementCount, arena);
2218      context->layoutElementChildren = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2219      context->openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2220      context->renderCommands = Clay_RenderCommandArray_Allocate_Arena(maxElementCount, arena);
2221      context->treeNodeVisited = Clay__boolArray_Allocate_Arena(maxElementCount, arena);
2222      context->treeNodeVisited.length = context->treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list
2223      context->openClipElementStack = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2224      context->reusableElementIndexBuffer = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2225      context->layoutElementClipElementIds = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2226      context->dynamicStringData = Clay__charArray_Allocate_Arena(maxElementCount, arena);
2227  }
2228  
2229  void Clay__InitializePersistentMemory(Clay_Context* context) {
2230      // Persistent memory - initialized once and not reset
2231      int32_t maxElementCount = context->maxElementCount;
2232      int32_t maxMeasureTextCacheWordCount = context->maxMeasureTextCacheWordCount;
2233      Clay_Arena *arena = &context->internalArena;
2234  
2235      context->scrollContainerDatas = Clay__ScrollContainerDataInternalArray_Allocate_Arena(100, arena);
2236      context->transitionDatas = Clay__TransitionDataInternalArray_Allocate_Arena(200, arena);
2237      context->layoutElementsHashMapInternal = Clay__LayoutElementHashMapItemArray_Allocate_Arena(maxElementCount, arena);
2238      context->layoutElementsHashMap = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2239      context->measureTextHashMapInternal = Clay__MeasureTextCacheItemArray_Allocate_Arena(maxElementCount, arena);
2240      context->measureTextHashMapInternalFreeList = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2241      context->measuredWordsFreeList = Clay__int32_tArray_Allocate_Arena(maxMeasureTextCacheWordCount, arena);
2242      context->measureTextHashMap = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
2243      context->measuredWords = Clay__MeasuredWordArray_Allocate_Arena(maxMeasureTextCacheWordCount, arena);
2244      context->pointerOverIds = Clay_ElementIdArray_Allocate_Arena(maxElementCount, arena);
2245      context->debugElementData = Clay__DebugElementDataArray_Allocate_Arena(maxElementCount, arena);
2246      context->arenaResetOffset = arena->nextAllocation;
2247  }
2248  
2249  const float CLAY__EPSILON = 0.01;
2250  
2251  bool Clay__FloatEqual(float left, float right) {
2252      float subtracted = left - right;
2253      return subtracted < CLAY__EPSILON && subtracted > -CLAY__EPSILON;
2254  }
2255  
2256  Clay_SizingAxis Clay__GetElementSizing(Clay_LayoutElement* element, bool xAxis) {
2257      if (element->isTextElement) {
2258          return CLAY__INIT(Clay_SizingAxis) {};
2259      } else {
2260          return xAxis ? element->config.layout.sizing.width : element->config.layout.sizing.height;
2261      }
2262  }
2263  
2264  // Writes out the location of text elements to layout elements buffer 1
2265  void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArray* textElementsOut, Clay__int32_tArray* aspectRatioElementsOut) {
2266      Clay_Context* context = Clay_GetCurrentContext();
2267      Clay__int32_tArray bfsBuffer = context->layoutElementChildrenBuffer;
2268      Clay__int32_tArray resizableContainerBuffer = context->openLayoutElementStack;
2269      for (int32_t rootIndex = 0; rootIndex < context->layoutElementTreeRoots.length; ++rootIndex) {
2270          bfsBuffer.length = 0;
2271          Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex);
2272          Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex);
2273          Clay__int32_tArray_Add(&bfsBuffer, (int32_t)root->layoutElementIndex);
2274  
2275          // Size floating containers to their parents
2276          if (rootElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
2277              Clay_FloatingElementConfig *floatingElementConfig = &rootElement->config.floating;
2278              Clay_LayoutElementHashMapItem *parentItem = Clay__GetHashMapItem(floatingElementConfig->parentId);
2279              if (parentItem && parentItem != &Clay_LayoutElementHashMapItem_DEFAULT) {
2280                  Clay_LayoutElement *parentLayoutElement = parentItem->layoutElement;
2281                  switch (rootElement->config.layout.sizing.width.type) {
2282                      case CLAY__SIZING_TYPE_GROW: {
2283                          rootElement->dimensions.width = parentLayoutElement->dimensions.width;
2284                          break;
2285                      }
2286                      case CLAY__SIZING_TYPE_PERCENT: {
2287                          rootElement->dimensions.width = parentLayoutElement->dimensions.width * rootElement->config.layout.sizing.width.size.percent;
2288                          break;
2289                      }
2290                      default: break;
2291                  }
2292                  switch (rootElement->config.layout.sizing.height.type) {
2293                      case CLAY__SIZING_TYPE_GROW: {
2294                          rootElement->dimensions.height = parentLayoutElement->dimensions.height;
2295                          break;
2296                      }
2297                      case CLAY__SIZING_TYPE_PERCENT: {
2298                          rootElement->dimensions.height = parentLayoutElement->dimensions.height * rootElement->config.layout.sizing.height.size.percent;
2299                          break;
2300                      }
2301                      default: break;
2302                  }
2303              }
2304          }
2305  
2306          if (rootElement->config.layout.sizing.width.type != CLAY__SIZING_TYPE_PERCENT) {
2307              rootElement->dimensions.width = CLAY__MIN(CLAY__MAX(rootElement->dimensions.width, rootElement->config.layout.sizing.width.size.minMax.min), rootElement->config.layout.sizing.width.size.minMax.max);
2308          }
2309          if (rootElement->config.layout.sizing.height.type != CLAY__SIZING_TYPE_PERCENT) {
2310              rootElement->dimensions.height = CLAY__MIN(CLAY__MAX(rootElement->dimensions.height, rootElement->config.layout.sizing.height.size.minMax.min), rootElement->config.layout.sizing.height.size.minMax.max);
2311          }
2312  
2313  
2314          for (int32_t i = 0; i < bfsBuffer.length; ++i) {
2315              int32_t parentIndex = Clay__int32_tArray_GetValue(&bfsBuffer, i);
2316              Clay_LayoutElement *parent = Clay_LayoutElementArray_Get(&context->layoutElements, parentIndex);
2317              Clay_LayoutConfig *parentLayoutConfig = &parent->config.layout;
2318              int32_t growContainerCount = 0;
2319              float parentSize = xAxis ? parent->dimensions.width : parent->dimensions.height;
2320              float parentPadding = (float)(xAxis ? (parentLayoutConfig->padding.left + parentLayoutConfig->padding.right) : (parentLayoutConfig->padding.top + parentLayoutConfig->padding.bottom));
2321              float innerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
2322              bool sizingAlongAxis = (xAxis && parentLayoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) || (!xAxis && parentLayoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM);
2323              resizableContainerBuffer.length = 0;
2324              float parentChildGap = parentLayoutConfig->childGap;
2325              bool isFirstChild = true;
2326  
2327              for (int32_t childOffset = 0; childOffset < parent->children.length; childOffset++) {
2328                  int32_t childElementIndex = parent->children.elements[childOffset];
2329                  Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex);
2330                  Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis);
2331                  float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height;
2332  
2333                  if (textElementsOut && childElement->isTextElement) {
2334                      Clay__int32_tArray_Add(textElementsOut, childElementIndex);
2335                  } else if (childElement->children.length > 0) {
2336                      Clay__int32_tArray_Add(&bfsBuffer, childElementIndex);
2337                  }
2338  
2339                  if (!childElement->isTextElement && aspectRatioElementsOut && childElement->config.aspectRatio.aspectRatio != 0) {
2340                      Clay__int32_tArray_Add(aspectRatioElementsOut, childElementIndex);
2341                  }
2342  
2343                  // Note: setting isFirstChild = false is skipped here
2344                  if (childElement->exiting) {
2345                      continue;
2346                  }
2347  
2348                  if (childSizing.type != CLAY__SIZING_TYPE_PERCENT
2349                      && childSizing.type != CLAY__SIZING_TYPE_FIXED
2350                      && (!childElement->isTextElement || childElement->textConfig.wrapMode == CLAY_TEXT_WRAP_WORDS)
2351  //                    && (xAxis || !Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT))
2352                  ) {
2353                      Clay__int32_tArray_Add(&resizableContainerBuffer, childElementIndex);
2354                  }
2355  
2356                  if (sizingAlongAxis) {
2357                      innerContentSize += (childSizing.type == CLAY__SIZING_TYPE_PERCENT ? 0 : childSize);
2358                      if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
2359                          growContainerCount++;
2360                      }
2361                      if (!isFirstChild) {
2362                          innerContentSize += parentChildGap; // For children after index 0, the childAxisOffset is the gap from the previous child
2363                          totalPaddingAndChildGaps += parentChildGap;
2364                      }
2365                  } else {
2366                      innerContentSize = CLAY__MAX(childSize, innerContentSize);
2367                  }
2368                  isFirstChild = false;
2369              }
2370  
2371              // Expand percentage containers to size
2372              for (int32_t childOffset = 0; childOffset < parent->children.length; childOffset++) {
2373                  int32_t childElementIndex = parent->children.elements[childOffset];
2374                  Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex);
2375                  Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis);
2376                  float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height;
2377                  if (childSizing.type == CLAY__SIZING_TYPE_PERCENT) {
2378                      *childSize = (parentSize - totalPaddingAndChildGaps) * childSizing.size.percent;
2379                      if (sizingAlongAxis) {
2380                          innerContentSize += *childSize;
2381                      }
2382                      Clay__UpdateAspectRatioBox(childElement);
2383                  }
2384              }
2385  
2386              if (sizingAlongAxis) {
2387                  float sizeToDistribute = parentSize - parentPadding - innerContentSize;
2388                  // The content is too large, compress the children as much as possible
2389                  if (sizeToDistribute < 0) {
2390                      // If the parent clips content in this axis direction, don't compress children, just leave them alone
2391                      if (((xAxis && parent->config.clip.horizontal) || (!xAxis && parent->config.clip.vertical))) {
2392                          continue;
2393                      }
2394                      // Scrolling containers preferentially compress before others
2395                      while (sizeToDistribute < -CLAY__EPSILON && resizableContainerBuffer.length > 0) {
2396                          float largest = 0;
2397                          float secondLargest = 0;
2398                          float widthToAdd = sizeToDistribute;
2399                          for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
2400                              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
2401                              float childSize = xAxis ? child->dimensions.width : child->dimensions.height;
2402                              if (Clay__FloatEqual(childSize, largest)) { continue; }
2403                              if (childSize > largest) {
2404                                  secondLargest = largest;
2405                                  largest = childSize;
2406                              }
2407                              if (childSize < largest) {
2408                                  secondLargest = CLAY__MAX(secondLargest, childSize);
2409                                  widthToAdd = secondLargest - largest;
2410                              }
2411                          }
2412  
2413                          widthToAdd = CLAY__MAX(widthToAdd, sizeToDistribute / resizableContainerBuffer.length);
2414  
2415                          for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
2416                              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
2417                              float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height;
2418                              float minSize = xAxis ? child->minDimensions.width : child->minDimensions.height;
2419                              float previousWidth = *childSize;
2420                              if (Clay__FloatEqual(*childSize, largest)) {
2421                                  *childSize += widthToAdd;
2422                                  if (*childSize <= minSize) {
2423                                      *childSize = minSize;
2424                                      Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
2425                                  }
2426                                  sizeToDistribute -= (*childSize - previousWidth);
2427                              }
2428                          }
2429                      }
2430                  // The content is too small, allow SIZING_GROW containers to expand
2431                  } else if (sizeToDistribute > 0 && growContainerCount > 0) {
2432                      for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
2433                          Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
2434                          Clay__SizingType childSizing = Clay__GetElementSizing(child, xAxis).type;
2435                          if (childSizing != CLAY__SIZING_TYPE_GROW) {
2436                              Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
2437                          }
2438                      }
2439                      while (sizeToDistribute > CLAY__EPSILON && resizableContainerBuffer.length > 0) {
2440                          float smallest = CLAY__MAXFLOAT;
2441                          float secondSmallest = CLAY__MAXFLOAT;
2442                          float widthToAdd = sizeToDistribute;
2443                          for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
2444                              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
2445                              float childSize = xAxis ? child->dimensions.width : child->dimensions.height;
2446                              if (Clay__FloatEqual(childSize, smallest)) { continue; }
2447                              if (childSize < smallest) {
2448                                  secondSmallest = smallest;
2449                                  smallest = childSize;
2450                              }
2451                              if (childSize > smallest) {
2452                                  secondSmallest = CLAY__MIN(secondSmallest, childSize);
2453                                  widthToAdd = secondSmallest - smallest;
2454                              }
2455                          }
2456  
2457                          widthToAdd = CLAY__MIN(widthToAdd, sizeToDistribute / resizableContainerBuffer.length);
2458  
2459                          for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
2460                              Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
2461                              float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height;
2462                              Clay_SizingAxis childSizing = Clay__GetElementSizing(child, xAxis);
2463                              float maxSize = childSizing.size.minMax.max;
2464                              float previousWidth = *childSize;
2465                              if (Clay__FloatEqual(*childSize, smallest)) {
2466                                  *childSize += widthToAdd;
2467                                  if (*childSize >= maxSize) {
2468                                      *childSize = maxSize;
2469                                      Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
2470                                  }
2471                                  sizeToDistribute -= (*childSize - previousWidth);
2472                              }
2473                          }
2474                      }
2475                  }
2476              // Sizing along the non layout axis ("off axis")
2477              } else {
2478                  for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) {
2479                      Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset));
2480                      Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis);
2481                      float minSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height;
2482                      float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height;
2483  
2484                      float maxSize = parentSize - parentPadding;
2485                      // If we're laying out the children of a scroll panel, grow containers expand to the size of the inner content, not the outer container
2486                      if (((xAxis && parent->config.clip.horizontal) || (!xAxis && parent->config.clip.vertical))) {
2487                          maxSize = CLAY__MAX(maxSize, innerContentSize);
2488                      }
2489                      if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
2490                          *childSize = CLAY__MIN(maxSize, childSizing.size.minMax.max);
2491                      }
2492                      *childSize = CLAY__MAX(minSize, CLAY__MIN(*childSize, maxSize));
2493                  }
2494              }
2495          }
2496      }
2497  }
2498  
2499  Clay_String Clay__IntToString(int32_t integer) {
2500      if (integer == 0) {
2501          return CLAY__INIT(Clay_String) { .length = 1, .chars = "0" };
2502      }
2503      Clay_Context* context = Clay_GetCurrentContext();
2504      char *chars = (char *)(context->dynamicStringData.internalArray + context->dynamicStringData.length);
2505      int32_t length = 0;
2506      int32_t sign = integer;
2507  
2508      if (integer < 0) {
2509          integer = -integer;
2510      }
2511      while (integer > 0) {
2512          chars[length++] = (char)(integer % 10 + '0');
2513          integer /= 10;
2514      }
2515  
2516      if (sign < 0) {
2517          chars[length++] = '-';
2518      }
2519  
2520      // Reverse the string to get the correct order
2521      for (int32_t j = 0, k = length - 1; j < k; j++, k--) {
2522          char temp = chars[j];
2523          chars[j] = chars[k];
2524          chars[k] = temp;
2525      }
2526      context->dynamicStringData.length += length;
2527      return CLAY__INIT(Clay_String) { .length = length, .chars = chars };
2528  }
2529  
2530  void Clay__AddRenderCommand(Clay_RenderCommand renderCommand) {
2531      Clay_Context* context = Clay_GetCurrentContext();
2532      if (context->renderCommands.length < context->renderCommands.capacity - 1) {
2533          Clay_RenderCommandArray_Add(&context->renderCommands, renderCommand);
2534      } else {
2535          if (!context->booleanWarnings.maxRenderCommandsExceeded) {
2536              context->booleanWarnings.maxRenderCommandsExceeded = true;
2537              context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
2538                  .errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
2539                  .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."),
2540                  .userData = context->errorHandler.userData });
2541          }
2542      }
2543  }
2544  
2545  bool Clay__ElementIsOffscreen(Clay_BoundingBox *boundingBox) {
2546      Clay_Context* context = Clay_GetCurrentContext();
2547      if (context->disableCulling) {
2548          return false;
2549      }
2550  
2551      return (boundingBox->x > (float)context->layoutDimensions.width) ||
2552             (boundingBox->y > (float)context->layoutDimensions.height) ||
2553             (boundingBox->x + boundingBox->width < 0) ||
2554             (boundingBox->y + boundingBox->height < 0);
2555  }
2556  
2557  void Clay__CalculateFinalLayout(float deltaTime, bool useStoredBoundingBoxes, bool generateRenderCommands) {
2558      Clay_Context* context = Clay_GetCurrentContext();
2559  
2560      // Calculate sizing along the X axis
2561      Clay__int32_tArray textElements = context->openClipElementStack;
2562      textElements.length = 0;
2563      Clay__int32_tArray aspectRatioElements = context->reusableElementIndexBuffer;
2564      aspectRatioElements.length = 0;
2565      Clay__SizeContainersAlongAxis(true, deltaTime, &textElements, &aspectRatioElements);
2566  
2567      // Wrap text
2568      for (int32_t textElementIndex = 0; textElementIndex < textElements.length; ++textElementIndex) {
2569          Clay_LayoutElement *element = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&textElements, textElementIndex));
2570          Clay__TextElementData *textElementData = &element->textElementData;
2571          textElementData->wrappedLines = CLAY__INIT(Clay__WrappedTextLineArraySlice) { .length = 0, .internalArray = &context->wrappedTextLines.internalArray[context->wrappedTextLines.length] };
2572          Clay_LayoutElement *containerElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&textElements, textElementIndex));
2573          Clay__MeasureTextCacheItem *measureTextCacheItem = Clay__MeasureTextCached(&textElementData->text, &containerElement->textConfig);
2574          float lineWidth = 0;
2575          float lineHeight = containerElement->textConfig.lineHeight > 0 ? (float)containerElement->textConfig.lineHeight : textElementData->preferredDimensions.height;
2576          int32_t lineLengthChars = 0;
2577          int32_t lineStartOffset = 0;
2578          if (!measureTextCacheItem->containsNewlines && textElementData->preferredDimensions.width <= containerElement->dimensions.width) {
2579              Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { containerElement->dimensions,  textElementData->text });
2580              textElementData->wrappedLines.length++;
2581              continue;
2582          }
2583          float spaceWidth = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = 1, .chars = CLAY__SPACECHAR.chars, .baseChars = CLAY__SPACECHAR.chars }, &containerElement->textConfig, context->measureTextUserData).width;
2584          int32_t wordIndex = measureTextCacheItem->measuredWordsStartIndex;
2585          while (wordIndex != -1) {
2586              if (context->wrappedTextLines.length > context->wrappedTextLines.capacity - 1) {
2587                  break;
2588              }
2589              Clay__MeasuredWord *measuredWord = Clay__MeasuredWordArray_Get(&context->measuredWords, wordIndex);
2590              // Only word on the line is too large, just render it anyway
2591              if (lineLengthChars == 0 && lineWidth + measuredWord->width > containerElement->dimensions.width) {
2592                  Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { measuredWord->width, lineHeight }, { .length = measuredWord->length, .chars = &textElementData->text.chars[measuredWord->startOffset] } });
2593                  textElementData->wrappedLines.length++;
2594                  wordIndex = measuredWord->next;
2595                  lineStartOffset = measuredWord->startOffset + measuredWord->length;
2596              }
2597              // measuredWord->length == 0 means a newline character
2598              else if (measuredWord->length == 0 || lineWidth + measuredWord->width > containerElement->dimensions.width) {
2599                  // Wrapped text lines list has overflowed, just render out the line
2600                  bool finalCharIsSpace = textElementData->text.chars[CLAY__MAX(lineStartOffset + lineLengthChars - 1, 0)] == ' ';
2601                  Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth + (finalCharIsSpace ? -spaceWidth : 0), lineHeight }, { .length = lineLengthChars + (finalCharIsSpace ? -1 : 0), .chars = &textElementData->text.chars[lineStartOffset] } });
2602                  textElementData->wrappedLines.length++;
2603                  if (lineLengthChars == 0 || measuredWord->length == 0) {
2604                      wordIndex = measuredWord->next;
2605                  }
2606                  lineWidth = 0;
2607                  lineLengthChars = 0;
2608                  lineStartOffset = measuredWord->startOffset;
2609              } else {
2610                  lineWidth += measuredWord->width + containerElement->textConfig.letterSpacing;
2611                  lineLengthChars += measuredWord->length;
2612                  wordIndex = measuredWord->next;
2613              }
2614          }
2615          if (lineLengthChars > 0) {
2616              Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth - containerElement->textConfig.letterSpacing, lineHeight }, {.length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } });
2617              textElementData->wrappedLines.length++;
2618          }
2619          containerElement->dimensions.height = lineHeight * (float)textElementData->wrappedLines.length;
2620      }
2621  
2622      // Scale vertical heights according to aspect ratio
2623      for (int32_t i = 0; i < aspectRatioElements.length; ++i) {
2624          Clay_LayoutElement* aspectElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&aspectRatioElements, i));
2625          aspectElement->dimensions.height = (1 / aspectElement->config.aspectRatio.aspectRatio) * aspectElement->dimensions.width;
2626          aspectElement->config.layout.sizing.height.size.minMax.max = aspectElement->dimensions.height;
2627      }
2628  
2629      // Propagate effect of text wrapping, aspect scaling etc. on height of parents
2630      Clay__LayoutElementTreeNodeArray dfsBuffer = context->layoutElementTreeNodeArray1;
2631      dfsBuffer.length = 0;
2632      for (int32_t i = 0; i < context->layoutElementTreeRoots.length; ++i) {
2633          Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, i);
2634          context->treeNodeVisited.internalArray[dfsBuffer.length] = false;
2635          Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex) });
2636      }
2637      while (dfsBuffer.length > 0) {
2638          Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1);
2639          Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement;
2640          if (!context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
2641              context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
2642              // If the element has no children or is the container for a text element, don't bother inspecting it
2643              if (currentElement->isTextElement || currentElement->children.length == 0) {
2644                  dfsBuffer.length--;
2645                  continue;
2646              }
2647              // Add the children to the DFS buffer (needs to be pushed in reverse so that stack traversal is in correct layout order)
2648              for (int32_t i = 0; i < currentElement->children.length; i++) {
2649                  context->treeNodeVisited.internalArray[dfsBuffer.length] = false;
2650                  Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]) });
2651              }
2652              continue;
2653          }
2654          dfsBuffer.length--;
2655  
2656          // DFS node has been visited, this is on the way back up to the root
2657          Clay_LayoutConfig *layoutConfig = &currentElement->config.layout;
2658          if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
2659              // Resize any parent containers that have grown in height along their non layout axis
2660              for (int32_t j = 0; j < currentElement->children.length; ++j) {
2661                  Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[j]);
2662                  float childHeightWithPadding = CLAY__MAX(childElement->dimensions.height + layoutConfig->padding.top + layoutConfig->padding.bottom, currentElement->dimensions.height);
2663                  currentElement->dimensions.height = CLAY__MIN(CLAY__MAX(childHeightWithPadding, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max);
2664              }
2665          } else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) {
2666              // Resizing along the layout axis
2667              float contentHeight = (float)(layoutConfig->padding.top + layoutConfig->padding.bottom);
2668              for (int32_t j = 0; j < currentElement->children.length; ++j) {
2669                  Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[j]);
2670                  contentHeight += childElement->dimensions.height;
2671              }
2672              contentHeight += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
2673              currentElement->dimensions.height = CLAY__MIN(CLAY__MAX(contentHeight, layoutConfig->sizing.height.size.minMax.min), layoutConfig->sizing.height.size.minMax.max);
2674          }
2675      }
2676  
2677      // Calculate sizing along the Y axis
2678      Clay__SizeContainersAlongAxis(false, deltaTime, NULL, NULL);
2679  
2680      // Scale horizontal widths according to aspect ratio
2681      for (int32_t i = 0; i < aspectRatioElements.length; ++i) {
2682          Clay_LayoutElement* aspectElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&aspectRatioElements, i));
2683          aspectElement->dimensions.width = aspectElement->config.aspectRatio.aspectRatio * aspectElement->dimensions.height;
2684      }
2685  
2686      // Sort tree roots by z-index
2687      int32_t sortMax = context->layoutElementTreeRoots.length - 1;
2688      while (sortMax > 0) { // todo dumb bubble sort
2689          for (int32_t i = 0; i < sortMax; ++i) {
2690              Clay__LayoutElementTreeRoot current = *Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, i);
2691              Clay__LayoutElementTreeRoot next = *Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, i + 1);
2692              if (next.zIndex < current.zIndex) {
2693                  Clay__LayoutElementTreeRootArray_Set(&context->layoutElementTreeRoots, i, next);
2694                  Clay__LayoutElementTreeRootArray_Set(&context->layoutElementTreeRoots, i + 1, current);
2695              }
2696          }
2697          sortMax--;
2698      }
2699  
2700      // Calculate final positions and generate render commands
2701      context->renderCommands.length = 0;
2702      dfsBuffer.length = 0;
2703  
2704      for (int32_t rootIndex = 0; rootIndex < context->layoutElementTreeRoots.length; ++rootIndex) {
2705          dfsBuffer.length = 0;
2706          Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex);
2707          Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)root->layoutElementIndex);
2708          Clay_Vector2 rootPosition = CLAY__DEFAULT_STRUCT;
2709          Clay_LayoutElementHashMapItem *parentHashMapItem = Clay__GetHashMapItem(root->parentId);
2710          // Position root floating containers
2711          if (rootElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE && parentHashMapItem) {
2712              Clay_FloatingElementConfig *config = &rootElement->config.floating;
2713              Clay_Dimensions rootDimensions = rootElement->dimensions;
2714              Clay_BoundingBox parentBoundingBox = parentHashMapItem->boundingBox;
2715              // Set X position
2716              Clay_Vector2 targetAttachPosition = CLAY__DEFAULT_STRUCT;
2717              switch (config->attachPoints.parent) {
2718                  case CLAY_ATTACH_POINT_LEFT_TOP:
2719                  case CLAY_ATTACH_POINT_LEFT_CENTER:
2720                  case CLAY_ATTACH_POINT_LEFT_BOTTOM: targetAttachPosition.x = parentBoundingBox.x; break;
2721                  case CLAY_ATTACH_POINT_CENTER_TOP:
2722                  case CLAY_ATTACH_POINT_CENTER_CENTER:
2723                  case CLAY_ATTACH_POINT_CENTER_BOTTOM: targetAttachPosition.x = parentBoundingBox.x + (parentBoundingBox.width / 2); break;
2724                  case CLAY_ATTACH_POINT_RIGHT_TOP:
2725                  case CLAY_ATTACH_POINT_RIGHT_CENTER:
2726                  case CLAY_ATTACH_POINT_RIGHT_BOTTOM: targetAttachPosition.x = parentBoundingBox.x + parentBoundingBox.width; break;
2727              }
2728              switch (config->attachPoints.element) {
2729                  case CLAY_ATTACH_POINT_LEFT_TOP:
2730                  case CLAY_ATTACH_POINT_LEFT_CENTER:
2731                  case CLAY_ATTACH_POINT_LEFT_BOTTOM: break;
2732                  case CLAY_ATTACH_POINT_CENTER_TOP:
2733                  case CLAY_ATTACH_POINT_CENTER_CENTER:
2734                  case CLAY_ATTACH_POINT_CENTER_BOTTOM: targetAttachPosition.x -= (rootDimensions.width / 2); break;
2735                  case CLAY_ATTACH_POINT_RIGHT_TOP:
2736                  case CLAY_ATTACH_POINT_RIGHT_CENTER:
2737                  case CLAY_ATTACH_POINT_RIGHT_BOTTOM: targetAttachPosition.x -= rootDimensions.width; break;
2738              }
2739              switch (config->attachPoints.parent) { // I know I could merge the x and y switch statements, but this is easier to read
2740                  case CLAY_ATTACH_POINT_LEFT_TOP:
2741                  case CLAY_ATTACH_POINT_RIGHT_TOP:
2742                  case CLAY_ATTACH_POINT_CENTER_TOP: targetAttachPosition.y = parentBoundingBox.y; break;
2743                  case CLAY_ATTACH_POINT_LEFT_CENTER:
2744                  case CLAY_ATTACH_POINT_CENTER_CENTER:
2745                  case CLAY_ATTACH_POINT_RIGHT_CENTER: targetAttachPosition.y = parentBoundingBox.y + (parentBoundingBox.height / 2); break;
2746                  case CLAY_ATTACH_POINT_LEFT_BOTTOM:
2747                  case CLAY_ATTACH_POINT_CENTER_BOTTOM:
2748                  case CLAY_ATTACH_POINT_RIGHT_BOTTOM: targetAttachPosition.y = parentBoundingBox.y + parentBoundingBox.height; break;
2749              }
2750              switch (config->attachPoints.element) {
2751                  case CLAY_ATTACH_POINT_LEFT_TOP:
2752                  case CLAY_ATTACH_POINT_RIGHT_TOP:
2753                  case CLAY_ATTACH_POINT_CENTER_TOP: break;
2754                  case CLAY_ATTACH_POINT_LEFT_CENTER:
2755                  case CLAY_ATTACH_POINT_CENTER_CENTER:
2756                  case CLAY_ATTACH_POINT_RIGHT_CENTER: targetAttachPosition.y -= (rootDimensions.height / 2); break;
2757                  case CLAY_ATTACH_POINT_LEFT_BOTTOM:
2758                  case CLAY_ATTACH_POINT_CENTER_BOTTOM:
2759                  case CLAY_ATTACH_POINT_RIGHT_BOTTOM: targetAttachPosition.y -= rootDimensions.height; break;
2760              }
2761              targetAttachPosition.x += config->offset.x;
2762              targetAttachPosition.y += config->offset.y;
2763              rootPosition = targetAttachPosition;
2764          }
2765          if (root->clipElementId) {
2766              Clay_LayoutElementHashMapItem *clipHashMapItem = Clay__GetHashMapItem(root->clipElementId);
2767              if (clipHashMapItem && !Clay__ElementIsOffscreen(&clipHashMapItem->boundingBox)) {
2768                  // Floating elements that are attached to scrolling contents won't be correctly positioned if external scroll handling is enabled, fix here
2769                  if (context->externalScrollHandlingEnabled) {
2770                      if (clipHashMapItem->layoutElement->config.clip.horizontal) {
2771                          rootPosition.x += clipHashMapItem->layoutElement->config.clip.childOffset.x;
2772                      }
2773                      if (clipHashMapItem->layoutElement->config.clip.vertical) {
2774                          rootPosition.y += clipHashMapItem->layoutElement->config.clip.childOffset.y;
2775                      }
2776                  }
2777                  if (generateRenderCommands) {
2778                      Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
2779                          .boundingBox = clipHashMapItem->boundingBox,
2780                          .userData = 0,
2781                          .id = Clay__HashNumber(rootElement->id, rootElement->children.length + 10).id, // TODO need a better strategy for managing derived ids
2782                          .zIndex = root->zIndex,
2783                          .commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
2784                      });
2785                  }
2786              }
2787          }
2788          Clay__LayoutElementTreeNodeArray_Add(&dfsBuffer, CLAY__INIT(Clay__LayoutElementTreeNode) { .layoutElement = rootElement, .position = rootPosition, .nextChildOffset = { .x = (float)rootElement->config.layout.padding.left, .y = (float)rootElement->config.layout.padding.top } });
2789  
2790          context->treeNodeVisited.internalArray[0] = false;
2791          while (dfsBuffer.length > 0) {
2792              Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1);
2793              Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement;
2794              Clay_LayoutConfig *layoutConfig = currentElement->isTextElement ? &CLAY_LAYOUT_DEFAULT : &currentElement->config.layout;
2795              Clay_Vector2 scrollOffset = CLAY__DEFAULT_STRUCT;
2796  
2797              // DFS is returning back upwards
2798              if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
2799                  if (currentElement->isTextElement) {
2800                      dfsBuffer.length--;
2801                      continue;
2802                  }
2803                  Clay_LayoutElementHashMapItem *currentElementData = Clay__GetHashMapItem(currentElement->id);
2804                  if (generateRenderCommands && !Clay__ElementIsOffscreen(&currentElementData->boundingBox)) {
2805                      // DFS is returning upwards backwards
2806                      bool closeClipElement = false;
2807                      if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
2808                          closeClipElement = true;
2809                          for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) {
2810                              Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
2811                              if (mapping->layoutElement == currentElement) {
2812                                  scrollOffset = currentElement->config.clip.childOffset;
2813                                  if (context->externalScrollHandlingEnabled) {
2814                                      scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
2815                                  }
2816                                  break;
2817                              }
2818                          }
2819                      }
2820  
2821                      if (Clay__BorderHasAnyWidth(&currentElement->config.border)) {
2822                          Clay_BoundingBox currentElementBoundingBox = currentElementData->boundingBox;
2823                          Clay_BorderElementConfig *borderConfig = &currentElement->config.border;
2824                          Clay_RenderCommand renderCommand = {
2825                              .boundingBox = currentElementBoundingBox,
2826                              .renderData = { .border = {
2827                                  .color = borderConfig->color,
2828                                  .cornerRadius = currentElement->config.cornerRadius,
2829                                  .width = borderConfig->width
2830                              }},
2831                              .userData = currentElement->config.userData,
2832                              .id = Clay__HashNumber(currentElement->id, currentElement->children.length).id,
2833                              .commandType = CLAY_RENDER_COMMAND_TYPE_BORDER,
2834                          };
2835                          Clay__AddRenderCommand(renderCommand);
2836                          if (borderConfig->width.betweenChildren > 0 && borderConfig->color.a > 0) {
2837                              float halfGap = layoutConfig->childGap / 2;
2838                              float halfWidth = borderConfig->width.betweenChildren / 2;
2839                              Clay_Vector2 borderOffset = { (float)layoutConfig->padding.left - halfGap, (float)layoutConfig->padding.top - halfGap };
2840                              if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
2841                                  for (int32_t i = 0; i < currentElement->children.length; ++i) {
2842                                      Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
2843                                      if (i > 0) {
2844                                          Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
2845                                                  .boundingBox = { currentElementBoundingBox.x + borderOffset.x + scrollOffset.x - halfWidth, currentElementBoundingBox.y + scrollOffset.y, (float)borderConfig->width.betweenChildren, currentElement->dimensions.height },
2846                                                  .renderData = { .rectangle = {
2847                                                          .backgroundColor = borderConfig->color,
2848                                                  } },
2849                                                  .userData = currentElement->config.userData,
2850                                                  .id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
2851                                                  .commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
2852                                          });
2853                                      }
2854                                      borderOffset.x += (childElement->dimensions.width + (float)layoutConfig->childGap);
2855                                  }
2856                              } else {
2857                                  for (int32_t i = 0; i < currentElement->children.length; ++i) {
2858                                      Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
2859                                      if (i > 0) {
2860                                          Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
2861                                                  .boundingBox = { currentElementBoundingBox.x + scrollOffset.x, currentElementBoundingBox.y + borderOffset.y + scrollOffset.y - halfWidth, currentElement->dimensions.width, (float)borderConfig->width.betweenChildren },
2862                                                  .renderData = { .rectangle = {
2863                                                          .backgroundColor = borderConfig->color,
2864                                                  } },
2865                                                  .userData = currentElement->config.userData,
2866                                                  .id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
2867                                                  .commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
2868                                          });
2869                                      }
2870                                      borderOffset.y += (childElement->dimensions.height + (float)layoutConfig->childGap);
2871                                  }
2872                              }
2873                          }
2874                      }
2875                      if (currentElement->config.overlayColor.a > 0) {
2876                          Clay_RenderCommand renderCommand = {
2877                                  .userData = currentElement->config.userData,
2878                                  .id = currentElement->id,
2879                                  .zIndex = root->zIndex,
2880                                  .commandType = CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_END,
2881                          };
2882                          Clay__AddRenderCommand(renderCommand);
2883                      }
2884                      // This exists because the scissor needs to end _after_ borders between elements
2885                      if (closeClipElement) {
2886                          Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
2887                                  .id = Clay__HashNumber(currentElement->id, rootElement->children.length + 11).id,
2888                                  .commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END,
2889                          });
2890                      }
2891                  }
2892  
2893                  dfsBuffer.length--;
2894                  continue;
2895              }
2896  
2897              // This will only be run a single time for each element in downwards DFS order
2898              context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
2899              Clay_BoundingBox currentElementBoundingBox = { currentElementTreeNode->position.x, currentElementTreeNode->position.y, currentElement->dimensions.width, currentElement->dimensions.height };
2900              Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL;
2901              if (!currentElement->isTextElement) {
2902                  if (useStoredBoundingBoxes && currentElement->config.transition.handler) {
2903                      bool found = false;
2904                      for (int j = 0; j < context->transitionDatas.length; ++j) {
2905                          Clay__TransitionDataInternal* transitionData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
2906                          if (transitionData->elementId == currentElement->id) {
2907                              found = true;
2908                              if (transitionData->state != CLAY_TRANSITION_STATE_IDLE) {
2909                                  if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_X) != 0) currentElementBoundingBox.x = transitionData->currentState.boundingBox.x;
2910                                  if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_Y) != 0) currentElementBoundingBox.y = transitionData->currentState.boundingBox.y;
2911                                  if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_WIDTH) != 0) currentElementBoundingBox.width = transitionData->currentState.boundingBox.width;
2912                                  if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) != 0) currentElementBoundingBox.height = transitionData->currentState.boundingBox.height;
2913                              }
2914                              break;
2915                          }
2916                      }
2917                      // An exiting element that completed its transition this frame - skip tree
2918                      if (!found && currentElement->config.transition.exit.setFinalState) {
2919                          dfsBuffer.length--;
2920                          continue;
2921                      }
2922                  }
2923                  if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
2924                      Clay_FloatingElementConfig *floatingElementConfig = &currentElement->config.floating;
2925                      Clay_Dimensions expand = floatingElementConfig->expand;
2926                      currentElementBoundingBox.x -= expand.width;
2927                      currentElementBoundingBox.width += expand.width * 2;
2928                      currentElementBoundingBox.y -= expand.height;
2929                      currentElementBoundingBox.height += expand.height * 2;
2930                  }
2931  
2932                  // Apply scroll offsets to container
2933                  if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
2934                      // 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
2935                      for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) {
2936                          Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
2937                          if (mapping->layoutElement == currentElement) {
2938                              scrollContainerData = mapping;
2939                              mapping->boundingBox = currentElementBoundingBox;
2940                              scrollOffset = currentElement->config.clip.childOffset;
2941                              if (context->externalScrollHandlingEnabled) {
2942                                  scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
2943                              }
2944                              break;
2945                          }
2946                      }
2947                  }
2948              }
2949  
2950              bool offscreen = Clay__ElementIsOffscreen(&currentElementBoundingBox);
2951  
2952              // Generate render commands for current element
2953              if (generateRenderCommands && !offscreen) {
2954                  if (currentElement->isTextElement) {
2955                      Clay_TextElementConfig *textElementConfig = &currentElement->textConfig;
2956                      float naturalLineHeight = currentElement->textElementData.preferredDimensions.height;
2957                      float finalLineHeight = textElementConfig->lineHeight > 0 ? (float)textElementConfig->lineHeight : naturalLineHeight;
2958                      float lineHeightOffset = (finalLineHeight - naturalLineHeight) / 2;
2959                      float yPosition = lineHeightOffset;
2960                      for (int32_t lineIndex = 0; lineIndex < currentElement->textElementData.wrappedLines.length; ++lineIndex) {
2961                          Clay__WrappedTextLine *wrappedLine = Clay__WrappedTextLineArraySlice_Get(&currentElement->textElementData.wrappedLines, lineIndex);
2962                          if (wrappedLine->line.length == 0) {
2963                              yPosition += finalLineHeight;
2964                              continue;
2965                          }
2966                          float offset = (currentElementBoundingBox.width - wrappedLine->dimensions.width);
2967                          if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_LEFT) {
2968                              offset = 0;
2969                          }
2970                          if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_CENTER) {
2971                              offset /= 2;
2972                          }
2973                          Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
2974                              .boundingBox = { currentElementBoundingBox.x + offset, currentElementBoundingBox.y + yPosition, wrappedLine->dimensions.width, wrappedLine->dimensions.height },
2975                              .renderData = { .text = {
2976                                  .stringContents = CLAY__INIT(Clay_StringSlice) { .length = wrappedLine->line.length, .chars = wrappedLine->line.chars, .baseChars = currentElement->textElementData.text.chars },
2977                                  .textColor = textElementConfig->textColor,
2978                                  .fontId = textElementConfig->fontId,
2979                                  .fontSize = textElementConfig->fontSize,
2980                                  .letterSpacing = textElementConfig->letterSpacing,
2981                                  .lineHeight = textElementConfig->lineHeight,
2982                              }},
2983                              .userData = textElementConfig->userData,
2984                              .id = Clay__HashNumber(lineIndex, currentElement->id).id,
2985                              .zIndex = root->zIndex,
2986                              .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT,
2987                          });
2988                          yPosition += finalLineHeight;
2989  
2990                          if (!context->disableCulling && (currentElementBoundingBox.y + yPosition > context->layoutDimensions.height)) {
2991                              break;
2992                          }
2993                      }
2994                  } else {
2995                      if (currentElement->config.overlayColor.a > 0) {
2996                          Clay_RenderCommand renderCommand = {
2997                              .renderData = {
2998                                  .overlayColor = { .color = currentElement->config.overlayColor }
2999                              },
3000                              .userData = currentElement->config.userData,
3001                              .id = currentElement->id,
3002                              .zIndex = root->zIndex,
3003                              .commandType = CLAY_RENDER_COMMAND_TYPE_OVERLAY_COLOR_START,
3004                          };
3005                          Clay__AddRenderCommand(renderCommand);
3006                      }
3007                      if (currentElement->config.image.imageData) {
3008                          Clay_RenderCommand renderCommand = {
3009                              .boundingBox = currentElementBoundingBox,
3010                              .renderData = {
3011                                  .image = {
3012                                      .backgroundColor = currentElement->config.backgroundColor,
3013                                      .cornerRadius = currentElement->config.cornerRadius,
3014                                      .imageData = currentElement->config.image.imageData,
3015                                  }
3016                              },
3017                              .userData = currentElement->config.userData,
3018                              .id = currentElement->id,
3019                              .zIndex = root->zIndex,
3020                                  .commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE,
3021                          };
3022                          Clay__AddRenderCommand(renderCommand);
3023                      }
3024                      if (currentElement->config.custom.customData) {
3025                          Clay_RenderCommand renderCommand = {
3026                              .boundingBox = currentElementBoundingBox,
3027                              .renderData = {
3028                                  .custom = {
3029                                      .backgroundColor = currentElement->config.backgroundColor,
3030                                      .cornerRadius = currentElement->config.cornerRadius,
3031                                      .customData = currentElement->config.custom.customData,
3032                                  }
3033                              },
3034                              .userData = currentElement->config.userData,
3035                              .id = currentElement->id,
3036                              .zIndex = root->zIndex,
3037                              .commandType = CLAY_RENDER_COMMAND_TYPE_CUSTOM,
3038                          };
3039                          Clay__AddRenderCommand(renderCommand);
3040                      }
3041                      if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
3042                          Clay_RenderCommand renderCommand = {
3043                              .boundingBox = currentElementBoundingBox,
3044                              .renderData = {
3045                                  .clip = {
3046                                      .horizontal = currentElement->config.clip.horizontal,
3047                                      .vertical = currentElement->config.clip.vertical,
3048                                  }
3049                              },
3050                              .userData = currentElement->config.userData,
3051                              .id = currentElement->id,
3052                              .zIndex = root->zIndex,
3053                              .commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
3054                          };
3055                          Clay__AddRenderCommand(renderCommand);
3056                      }
3057                      if (currentElement->config.backgroundColor.a > 0) {
3058                          Clay_RenderCommand renderCommand = {
3059                              .boundingBox = currentElementBoundingBox,
3060                              .renderData = { .rectangle = {
3061                                  .backgroundColor = currentElement->config.backgroundColor,
3062                                  .cornerRadius = currentElement->config.cornerRadius,
3063                              } },
3064                              .userData = currentElement->config.userData,
3065                              .id = currentElement->id,
3066                              .zIndex = root->zIndex,
3067                              .commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
3068                          };
3069                          Clay__AddRenderCommand(renderCommand);
3070                      }
3071                  }
3072              }
3073  
3074              Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(currentElement->id);
3075              hashMapItem->boundingBox = currentElementBoundingBox;
3076  
3077              if (currentElement->isTextElement) continue;
3078  
3079              // Setup positions for child elements and add to DFS buffer ----------
3080  
3081              // On-axis alignment
3082              Clay_Dimensions contentSizeCurrent = {};
3083              if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
3084                  for (int32_t i = 0; i < currentElement->children.length; ++i) {
3085                      Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
3086                      if (childElement->exiting) continue;
3087                      contentSizeCurrent.width += childElement->dimensions.width;
3088                      contentSizeCurrent.height = CLAY__MAX(contentSizeCurrent.height, childElement->dimensions.height);
3089                  }
3090                  contentSizeCurrent.width += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
3091                  float extraSpace = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - contentSizeCurrent.width;
3092                  switch (layoutConfig->childAlignment.x) {
3093                      case CLAY_ALIGN_X_LEFT: extraSpace = 0; break;
3094                      case CLAY_ALIGN_X_CENTER: extraSpace /= 2; break;
3095                      default: break;
3096                  }
3097                  extraSpace = CLAY__MAX(0, extraSpace);
3098                  currentElementTreeNode->nextChildOffset.x += extraSpace;
3099              } else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) {
3100                  for (int32_t i = 0; i < currentElement->children.length; ++i) {
3101                      Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
3102                      if (childElement->exiting) continue;
3103                      contentSizeCurrent.width = CLAY__MAX(contentSizeCurrent.width, childElement->dimensions.width);
3104                      contentSizeCurrent.height += childElement->dimensions.height;
3105                  }
3106                  contentSizeCurrent.height += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
3107                  float extraSpace = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - contentSizeCurrent.height;
3108                  switch (layoutConfig->childAlignment.y) {
3109                      case CLAY_ALIGN_Y_TOP: extraSpace = 0; break;
3110                      case CLAY_ALIGN_Y_CENTER: extraSpace /= 2; break;
3111                      default: break;
3112                  }
3113                  extraSpace = CLAY__MAX(0, extraSpace);
3114                  currentElementTreeNode->nextChildOffset.y += extraSpace;
3115              }
3116  
3117              if (scrollContainerData) {
3118                  scrollContainerData->contentSize = CLAY__INIT(Clay_Dimensions) {contentSizeCurrent.width + (float)(layoutConfig->padding.left + layoutConfig->padding.right), contentSizeCurrent.height + (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) };
3119              }
3120  
3121              // Add children to the DFS buffer
3122              dfsBuffer.length += currentElement->children.length;
3123              for (int32_t i = 0; i < currentElement->children.length; ++i) {
3124                  Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
3125                  Clay_LayoutElementHashMapItem* childMapItem = Clay__GetHashMapItem(childElement->id);
3126                  // Alignment along non layout axis
3127                  if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
3128                      currentElementTreeNode->nextChildOffset.y = currentElement->config.layout.padding.top;
3129                      float whiteSpaceAroundChild = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - childElement->dimensions.height;
3130                      switch (layoutConfig->childAlignment.y) {
3131                          case CLAY_ALIGN_Y_TOP: break;
3132                          case CLAY_ALIGN_Y_CENTER: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild / 2; break;
3133                          case CLAY_ALIGN_Y_BOTTOM: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild; break;
3134                      }
3135                  } else {
3136                      currentElementTreeNode->nextChildOffset.x = currentElement->config.layout.padding.left;
3137                      float whiteSpaceAroundChild = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - childElement->dimensions.width;
3138                      switch (layoutConfig->childAlignment.x) {
3139                          case CLAY_ALIGN_X_LEFT: break;
3140                          case CLAY_ALIGN_X_CENTER: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild / 2; break;
3141                          case CLAY_ALIGN_X_RIGHT: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild; break;
3142                      }
3143                  }
3144  
3145                  Clay_Vector2 childPosition = {
3146                      currentElementBoundingBox.x + currentElementTreeNode->nextChildOffset.x + scrollOffset.x,
3147                      currentElementBoundingBox.y + currentElementTreeNode->nextChildOffset.y + scrollOffset.y,
3148                  };
3149  
3150                  // DFS buffer elements need to be added in reverse because stack traversal happens backwards
3151                  uint32_t newNodeIndex = dfsBuffer.length - 1 - i;
3152                  dfsBuffer.internalArray[newNodeIndex] = CLAY__INIT(Clay__LayoutElementTreeNode) {
3153                      .layoutElement = childElement,
3154                      .position = CLAY__INIT(Clay_Vector2) { childPosition.x, childPosition.y },
3155                      .nextChildOffset = { .x = (float)childElement->config.layout.padding.left, .y = (float)childElement->config.layout.padding.top },
3156                  };
3157                  context->treeNodeVisited.internalArray[newNodeIndex] = false;
3158  
3159                  // Update parent offsets
3160                  if (!childElement->exiting) {
3161                      if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
3162                          currentElementTreeNode->nextChildOffset.x += childElement->dimensions.width + (float)layoutConfig->childGap;
3163                      } else {
3164                          currentElementTreeNode->nextChildOffset.y += childElement->dimensions.height + (float)layoutConfig->childGap;
3165                      }
3166                  }
3167              }
3168          }
3169  
3170          if (root->clipElementId) {
3171              Clay_LayoutElementHashMapItem *clipHashMapItem = Clay__GetHashMapItem(root->clipElementId);
3172              if (clipHashMapItem && !Clay__ElementIsOffscreen(&clipHashMapItem->boundingBox)) {
3173                  Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) { .id = Clay__HashNumber(rootElement->id, rootElement->children.length + 11).id, .commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END });
3174              }
3175          }
3176      }
3177  }
3178  
3179  CLAY_WASM_EXPORT("Clay_GetPointerOverIds")
3180  CLAY_DLL_EXPORT Clay_ElementIdArray Clay_GetPointerOverIds(void) {
3181      return Clay_GetCurrentContext()->pointerOverIds;
3182  }
3183  
3184  #pragma region DebugTools
3185  Clay_Color CLAY__DEBUGVIEW_COLOR_1 = {58, 56, 52, 255};
3186  Clay_Color CLAY__DEBUGVIEW_COLOR_2 = {62, 60, 58, 255};
3187  Clay_Color CLAY__DEBUGVIEW_COLOR_3 = {141, 133, 135, 255};
3188  Clay_Color CLAY__DEBUGVIEW_COLOR_4 = {238, 226, 231, 255};
3189  Clay_Color CLAY__DEBUGVIEW_COLOR_SELECTED_ROW = {102, 80, 78, 255};
3190  const int32_t CLAY__DEBUGVIEW_ROW_HEIGHT = 30;
3191  const int32_t CLAY__DEBUGVIEW_OUTER_PADDING = 10;
3192  const int32_t CLAY__DEBUGVIEW_INDENT_WIDTH = 16;
3193  Clay_TextElementConfig Clay__DebugView_TextNameConfig = {.textColor = {238, 226, 231, 255}, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE };
3194  Clay_LayoutConfig Clay__DebugView_ScrollViewItemLayoutConfig = CLAY__DEFAULT_STRUCT;
3195  
3196  typedef struct {
3197      Clay_String label;
3198      Clay_Color color;
3199  } Clay__DebugElementConfigTypeLabelConfig;
3200  
3201  typedef enum {
3202      CLAY__ELEMENT_CONFIG_TYPE_BACKGROUND_COLOR,
3203      CLAY__ELEMENT_CONFIG_TYPE_OVERLAY_COLOR,
3204      CLAY__ELEMENT_CONFIG_TYPE_CORNER_RADIUS,
3205      CLAY__ELEMENT_CONFIG_TYPE_TEXT,
3206      CLAY__ELEMENT_CONFIG_TYPE_ASPECT,
3207      CLAY__ELEMENT_CONFIG_TYPE_IMAGE,
3208      CLAY__ELEMENT_CONFIG_TYPE_FLOATING,
3209      CLAY__ELEMENT_CONFIG_TYPE_CLIP,
3210      CLAY__ELEMENT_CONFIG_TYPE_BORDER,
3211      CLAY__ELEMENT_CONFIG_TYPE_CUSTOM,
3212  } Clay__DebugElementConfigType;
3213  
3214  Clay__DebugElementConfigTypeLabelConfig Clay__DebugGetElementConfigTypeLabel(Clay__DebugElementConfigType type) {
3215      switch (type) {
3216          case CLAY__ELEMENT_CONFIG_TYPE_BACKGROUND_COLOR: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Background"), {243,134,48,255} };
3217          case CLAY__ELEMENT_CONFIG_TYPE_OVERLAY_COLOR: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Overlay"), { 142,129,206, 255} };
3218          case CLAY__ELEMENT_CONFIG_TYPE_CORNER_RADIUS: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Radius"), {239,148,157, 255 } };
3219          case CLAY__ELEMENT_CONFIG_TYPE_TEXT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Text"), {105,210,231,255} };
3220          case CLAY__ELEMENT_CONFIG_TYPE_ASPECT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Aspect"), {101,149,194,255} };
3221          case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Image"), {121,189,154,255} };
3222          case CLAY__ELEMENT_CONFIG_TYPE_FLOATING: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Floating"), {250,105,0,255} };
3223          case CLAY__ELEMENT_CONFIG_TYPE_CLIP: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Scroll"), {242, 196, 90, 255} };
3224          case CLAY__ELEMENT_CONFIG_TYPE_BORDER: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Border"), {108, 91, 123, 255} };
3225          case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Custom"), {11,72,107,255} };
3226          default: break;
3227      }
3228      return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Error"), {0,0,0,255} };
3229  }
3230  
3231  void Clay__RenderElementConfigTypeLabel(Clay_String label, Clay_Color color, bool offscreen) {
3232      Clay_Color backgroundColor = color;
3233      backgroundColor.a = 90;
3234      CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 } }, .backgroundColor = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4), .border = { .color = color, .width = { 1, 1, 1, 1, 0 } } }) {
3235          CLAY_TEXT(label, CLAY_TEXT_CONFIG({ .textColor = offscreen ? CLAY__DEBUGVIEW_COLOR_3 : CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3236      }
3237  }
3238  
3239  typedef struct {
3240      int32_t rowCount;
3241      int32_t selectedElementRowIndex;
3242  } Clay__RenderDebugLayoutData;
3243  
3244  // Returns row count
3245  Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialRootsLength, int32_t highlightedRowIndex) {
3246      Clay_Context* context = Clay_GetCurrentContext();
3247      Clay__int32_tArray dfsBuffer = context->reusableElementIndexBuffer;
3248      Clay__DebugView_ScrollViewItemLayoutConfig = CLAY__INIT(Clay_LayoutConfig) { .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT) }, .childGap = 6, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }};
3249      Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT;
3250  
3251      uint32_t highlightedElementId = 0;
3252  
3253      for (int32_t rootIndex = 0; rootIndex < initialRootsLength; ++rootIndex) {
3254          dfsBuffer.length = 0;
3255          Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex);
3256          Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex);
3257          context->treeNodeVisited.internalArray[0] = false;
3258          if (rootIndex > 0) {
3259              CLAY(CLAY_IDI("Clay__DebugView_EmptyRowOuter", rootIndex), { .layout = { .sizing = {.width = CLAY_SIZING_GROW(0)}, .padding = {CLAY__DEBUGVIEW_INDENT_WIDTH / 2, 0, 0, 0} } }) {
3260                  CLAY(CLAY_IDI("Clay__DebugView_EmptyRow", rootIndex), { .layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED((float)CLAY__DEBUGVIEW_ROW_HEIGHT) }}, .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = { .top = 1 } } }) {}
3261              }
3262              layoutData.rowCount++;
3263          }
3264          while (dfsBuffer.length > 0) {
3265              int32_t currentElementIndex = Clay__int32_tArray_GetValue(&dfsBuffer, (int)dfsBuffer.length - 1);
3266              Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, (int)currentElementIndex);
3267              if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
3268                  if (!currentElement->isTextElement && currentElement->children.length > 0) {
3269                      Clay__CloseElement();
3270                      Clay__CloseElement();
3271                      Clay__CloseElement();
3272                  }
3273                  dfsBuffer.length--;
3274                  continue;
3275              }
3276  
3277              if (currentElement->exiting) { // TODO there is a duplicate ID problem with exiting elements
3278                  dfsBuffer.length--;
3279                  continue;
3280              }
3281  
3282              if (highlightedRowIndex == layoutData.rowCount) {
3283                  if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
3284                      context->debugSelectedElementId = currentElement->id;
3285                  }
3286                  highlightedElementId = currentElement->id;
3287              }
3288  
3289              context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
3290              Clay_LayoutElementHashMapItem *currentElementData = Clay__GetHashMapItem(currentElement->id);
3291              bool offscreen = Clay__ElementIsOffscreen(&currentElementData->boundingBox);
3292              if (context->debugSelectedElementId == currentElement->id) {
3293                  layoutData.selectedElementRowIndex = layoutData.rowCount;
3294              }
3295              CLAY(CLAY_IDI("Clay__DebugView_ElementOuter", currentElement->id), { .layout = Clay__DebugView_ScrollViewItemLayoutConfig }) {
3296                  // Collapse icon / button
3297                  if (!(currentElement->isTextElement || currentElement->children.length == 0)) {
3298                      CLAY(CLAY_IDI("Clay__DebugView_CollapseElement", currentElement->id), {
3299                          .layout = { .sizing = {CLAY_SIZING_FIXED(16), CLAY_SIZING_FIXED(16)}, .childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER} },
3300                          .cornerRadius = CLAY_CORNER_RADIUS(4),
3301                          .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = {1, 1, 1, 1, 0} },
3302                      }) {
3303                          CLAY_TEXT((currentElementData && currentElementData->debugData->collapsed) ? CLAY_STRING("+") : CLAY_STRING("-"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3304                      }
3305                  } else { // Square dot for empty containers
3306                      CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_FIXED(16), CLAY_SIZING_FIXED(16)}, .childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER } } }) {
3307                          CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_FIXED(8), CLAY_SIZING_FIXED(8)} }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_3, .cornerRadius = CLAY_CORNER_RADIUS(2) }) {}
3308                      }
3309                  }
3310                  // Collisions and offscreen info
3311                  if (currentElementData) {
3312                      if (currentElementData->debugData->collision) {
3313                          CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 }}, .border = { .color = {177, 147, 8, 255}, .width = {1, 1, 1, 1, 0} } }) {
3314                              CLAY_TEXT(CLAY_STRING("Duplicate ID"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 }));
3315                          }
3316                      }
3317                      if (offscreen) {
3318                          CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 } }, .border = {  .color = CLAY__DEBUGVIEW_COLOR_3, .width = { 1, 1, 1, 1, 0} } }) {
3319                              CLAY_TEXT(CLAY_STRING("Offscreen"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 }));
3320                          }
3321                      }
3322                  }
3323                  if (currentElementData->elementId.stringId.length > 0) {
3324                      CLAY_AUTO_ID() {
3325                          Clay_TextElementConfig textConfig = offscreen ? CLAY__INIT(Clay_TextElementConfig) { .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 } : Clay__DebugView_TextNameConfig;
3326                          CLAY_TEXT(currentElementData->elementId.stringId, textConfig);
3327                          if (currentElementData->elementId.offset != 0) {
3328                              CLAY_TEXT(CLAY_STRING(" ("), textConfig);
3329                              CLAY_TEXT(Clay__IntToString(currentElementData->elementId.offset), textConfig);
3330                              CLAY_TEXT(CLAY_STRING(")"), textConfig);
3331                          }
3332                      }
3333                  }
3334                  if (currentElement->isTextElement) {
3335                      Clay__RenderElementConfigTypeLabel(CLAY_STRING("Text"), CLAY__INIT(Clay_Color) { 105,210,231,255 }, offscreen);
3336                  } else {
3337                      if (currentElement->config.backgroundColor.a > 0) {
3338                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_BACKGROUND_COLOR);
3339                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3340                      }
3341                      if (currentElement->config.overlayColor.a > 0) {
3342                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_OVERLAY_COLOR);
3343                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3344                      }
3345                      if (!Clay__MemCmp((const char*)&currentElement->config.cornerRadius, (const char*)&Clay__CornerRadius_DEFAULT, sizeof(Clay_CornerRadius))) {
3346                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_CORNER_RADIUS);
3347                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3348                      }
3349                      if (currentElement->config.aspectRatio.aspectRatio != 0) {
3350                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_ASPECT);
3351                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3352                      }
3353                      if (currentElement->config.image.imageData) {
3354                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_IMAGE);
3355                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3356                      }
3357                      if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
3358                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_FLOATING);
3359                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3360                      }
3361                      if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
3362                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_CLIP);
3363                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3364                      }
3365                      if (Clay__BorderHasAnyWidth(&currentElement->config.border)) {
3366                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_BORDER);
3367                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3368                      }
3369                      if (currentElement->config.custom.customData) {
3370                          Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_CUSTOM);
3371                          Clay__RenderElementConfigTypeLabel(config.label, config.color, offscreen);
3372                      }
3373                  }
3374              }
3375  
3376              // Render the text contents below the element as a non-interactive row
3377              if (currentElement->isTextElement) {
3378                  layoutData.rowCount++;
3379                  Clay__TextElementData *textElementData = &currentElement->textElementData;
3380                  Clay_TextElementConfig rawTextConfig = offscreen ? CLAY__INIT(Clay_TextElementConfig) { .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 } : Clay__DebugView_TextNameConfig;
3381                  CLAY_AUTO_ID({ .layout = { .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } } }) {
3382                      CLAY_AUTO_ID({ .layout = { .sizing = {.width = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_INDENT_WIDTH + 16) } } }) {}
3383                      CLAY_TEXT(CLAY_STRING("\""), rawTextConfig);
3384                      CLAY_TEXT(textElementData->text.length > 40 ? (CLAY__INIT(Clay_String) { .length = 40, .chars = textElementData->text.chars }) : textElementData->text, rawTextConfig);
3385                      if (textElementData->text.length > 40) {
3386                          CLAY_TEXT(CLAY_STRING("..."), rawTextConfig);
3387                      }
3388                      CLAY_TEXT(CLAY_STRING("\""), rawTextConfig);
3389                  }
3390              } else if (currentElement->children.length > 0) {
3391                  Clay__OpenElement();
3392                  Clay__ConfigureOpenElement(CLAY__INIT(Clay_ElementDeclaration) { .layout = { .padding = { .left = 8 } } });
3393                  Clay__OpenElement();
3394                  Clay__ConfigureOpenElement(CLAY__INIT(Clay_ElementDeclaration) { .layout = { .padding = { .left = CLAY__DEBUGVIEW_INDENT_WIDTH }}, .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = { .left = 1 } }});
3395                  Clay__OpenElement();
3396                  Clay__ConfigureOpenElement(CLAY__INIT(Clay_ElementDeclaration) { .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM } });
3397              }
3398  
3399              layoutData.rowCount++;
3400              if (!(currentElement->isTextElement || (currentElementData && currentElementData->debugData->collapsed))) {
3401                  for (int32_t i = currentElement->children.length - 1; i >= 0; --i) {
3402                      Clay__int32_tArray_Add(&dfsBuffer, currentElement->children.elements[i]);
3403                      context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked
3404                  }
3405              }
3406          }
3407      }
3408  
3409      if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
3410          Clay_ElementId collapseButtonId = Clay__HashString(CLAY_STRING("Clay__DebugView_CollapseElement"), 0);
3411          for (int32_t i = (int)context->pointerOverIds.length - 1; i >= 0; i--) {
3412              Clay_ElementId *elementId = Clay_ElementIdArray_Get(&context->pointerOverIds, i);
3413              if (elementId->baseId == collapseButtonId.baseId) {
3414                  Clay_LayoutElementHashMapItem *highlightedItem = Clay__GetHashMapItem(elementId->offset);
3415                  highlightedItem->debugData->collapsed = !highlightedItem->debugData->collapsed;
3416                  break;
3417              }
3418          }
3419      }
3420  
3421      if (highlightedElementId) {
3422          CLAY(CLAY_ID("Clay__DebugView_ElementHighlight"), { .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .floating = { .parentId = highlightedElementId, .zIndex = 32767, .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID } }) {
3423              CLAY(CLAY_ID("Clay__DebugView_ElementHighlightRectangle"), { .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .backgroundColor = Clay__debugViewHighlightColor }) {}
3424          }
3425      }
3426      return layoutData;
3427  }
3428  
3429  void Clay__RenderDebugLayoutSizing(Clay_SizingAxis sizing, Clay_TextElementConfig infoTextConfig) {
3430      Clay_String sizingLabel = CLAY_STRING("GROW");
3431      if (sizing.type == CLAY__SIZING_TYPE_FIT) {
3432          sizingLabel = CLAY_STRING("FIT");
3433      } else if (sizing.type == CLAY__SIZING_TYPE_PERCENT) {
3434          sizingLabel = CLAY_STRING("PERCENT");
3435      } else if (sizing.type == CLAY__SIZING_TYPE_FIXED) {
3436          sizingLabel = CLAY_STRING("FIXED");
3437      }
3438      CLAY_TEXT(sizingLabel, infoTextConfig);
3439      if (sizing.type == CLAY__SIZING_TYPE_GROW || sizing.type == CLAY__SIZING_TYPE_FIT || sizing.type == CLAY__SIZING_TYPE_FIXED) {
3440          CLAY_TEXT(CLAY_STRING("("), infoTextConfig);
3441          if (sizing.size.minMax.min != 0) {
3442              CLAY_TEXT(CLAY_STRING("min: "), infoTextConfig);
3443              CLAY_TEXT(Clay__IntToString(sizing.size.minMax.min), infoTextConfig);
3444              if (sizing.size.minMax.max != CLAY__MAXFLOAT) {
3445                  CLAY_TEXT(CLAY_STRING(", "), infoTextConfig);
3446              }
3447          }
3448          if (sizing.size.minMax.max != CLAY__MAXFLOAT) {
3449              CLAY_TEXT(CLAY_STRING("max: "), infoTextConfig);
3450              CLAY_TEXT(Clay__IntToString(sizing.size.minMax.max), infoTextConfig);
3451          }
3452          CLAY_TEXT(CLAY_STRING(")"), infoTextConfig);
3453      } else if (sizing.type == CLAY__SIZING_TYPE_PERCENT) {
3454          CLAY_TEXT(CLAY_STRING("("), infoTextConfig);
3455          CLAY_TEXT(Clay__IntToString(sizing.size.percent * 100), infoTextConfig);
3456          CLAY_TEXT(CLAY_STRING("%)"), infoTextConfig);
3457      }
3458  }
3459  
3460  void Clay__DebugViewRenderElementConfigHeader(Clay_String elementId, Clay__DebugElementConfigType type) {
3461      Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(type);
3462      Clay_Color backgroundColor = config.color;
3463      backgroundColor.a = 90;
3464      CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 } }, .backgroundColor = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4), .border = { .color = config.color, .width = { 1, 1, 1, 1, 0 } } }) {
3465          CLAY_TEXT(config.label, CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3466      }
3467  }
3468  
3469  void Clay__RenderDebugViewColor(Clay_Color color, Clay_TextElementConfig textConfig) {
3470      CLAY_AUTO_ID({ .layout = { .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) {
3471          CLAY_TEXT(CLAY_STRING("{ r: "), textConfig);
3472          CLAY_TEXT(Clay__IntToString(color.r), textConfig);
3473          CLAY_TEXT(CLAY_STRING(", g: "), textConfig);
3474          CLAY_TEXT(Clay__IntToString(color.g), textConfig);
3475          CLAY_TEXT(CLAY_STRING(", b: "), textConfig);
3476          CLAY_TEXT(Clay__IntToString(color.b), textConfig);
3477          CLAY_TEXT(CLAY_STRING(", a: "), textConfig);
3478          CLAY_TEXT(Clay__IntToString(color.a), textConfig);
3479          CLAY_TEXT(CLAY_STRING(" }"), textConfig);
3480          CLAY_AUTO_ID({ .layout = { .sizing = { .width = CLAY_SIZING_FIXED(10) } } }) {}
3481          CLAY_AUTO_ID({ .layout = { .sizing = { CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8)} }, .backgroundColor = color, .cornerRadius = CLAY_CORNER_RADIUS(4), .border = { .color = CLAY__DEBUGVIEW_COLOR_4, .width = { 1, 1, 1, 1, 0 } } }) {}
3482      }
3483  }
3484  
3485  void Clay__RenderDebugViewCornerRadius(Clay_CornerRadius cornerRadius, Clay_TextElementConfig textConfig) {
3486      CLAY_AUTO_ID({ .layout = { .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) {
3487          CLAY_TEXT(CLAY_STRING("{ topLeft: "), textConfig);
3488          CLAY_TEXT(Clay__IntToString(cornerRadius.topLeft), textConfig);
3489          CLAY_TEXT(CLAY_STRING(", topRight: "), textConfig);
3490          CLAY_TEXT(Clay__IntToString(cornerRadius.topRight), textConfig);
3491          CLAY_TEXT(CLAY_STRING(", bottomLeft: "), textConfig);
3492          CLAY_TEXT(Clay__IntToString(cornerRadius.bottomLeft), textConfig);
3493          CLAY_TEXT(CLAY_STRING(", bottomRight: "), textConfig);
3494          CLAY_TEXT(Clay__IntToString(cornerRadius.bottomRight), textConfig);
3495          CLAY_TEXT(CLAY_STRING(" }"), textConfig);
3496      }
3497  }
3498  
3499  void HandleDebugViewCloseButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerInfo, void *userData) {
3500      Clay_Context* context = Clay_GetCurrentContext();
3501      (void) elementId; (void) pointerInfo; (void) userData;
3502      if (pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
3503          context->debugModeEnabled = false;
3504      }
3505  }
3506  
3507  void Clay__RenderDebugView(void) {
3508      Clay_Context* context = Clay_GetCurrentContext();
3509      Clay_ElementId closeButtonId = Clay__HashString(CLAY_STRING("Clay__DebugViewTopHeaderCloseButtonOuter"), 0);
3510      if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
3511          for (int32_t i = 0; i < context->pointerOverIds.length; ++i) {
3512              Clay_ElementId *elementId = Clay_ElementIdArray_Get(&context->pointerOverIds, i);
3513              if (elementId->id == closeButtonId.id) {
3514                  context->debugModeEnabled = false;
3515                  return;
3516              }
3517          }
3518      }
3519  
3520      uint32_t initialRootsLength = context->layoutElementTreeRoots.length;
3521      uint32_t initialElementsLength = context->layoutElements.length;
3522      Clay_TextElementConfig infoTextConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE });
3523      Clay_TextElementConfig infoTitleConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE });
3524      Clay_ElementId scrollId = Clay__HashString(CLAY_STRING("Clay__DebugViewOuterScrollPane"), 0);
3525      float scrollYOffset = 0;
3526      bool pointerInDebugView = context->pointerInfo.position.y < context->layoutDimensions.height - 300;
3527      for (int32_t i = 0; i < context->scrollContainerDatas.length; ++i) {
3528          Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
3529          if (scrollContainerData->elementId == scrollId.id) {
3530              if (!context->externalScrollHandlingEnabled) {
3531                  scrollYOffset = scrollContainerData->scrollPosition.y;
3532              } else {
3533                  pointerInDebugView = context->pointerInfo.position.y + scrollContainerData->scrollPosition.y < context->layoutDimensions.height - 300;
3534              }
3535              break;
3536          }
3537      }
3538      int32_t highlightedRow = pointerInDebugView
3539              ? (int32_t)((context->pointerInfo.position.y - scrollYOffset) / (float)CLAY__DEBUGVIEW_ROW_HEIGHT) - 1
3540              : -1;
3541      if (context->pointerInfo.position.x < context->layoutDimensions.width - (float)Clay__debugViewWidth) {
3542          highlightedRow = -1;
3543      }
3544      Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT;
3545      CLAY(CLAY_ID("Clay__DebugView"), {
3546           .layout = { .sizing = { CLAY_SIZING_FIXED((float)Clay__debugViewWidth) , CLAY_SIZING_FIXED(context->layoutDimensions.height) }, .layoutDirection = CLAY_TOP_TO_BOTTOM },
3547          .floating = { .zIndex = 32765, .attachPoints = { .element = CLAY_ATTACH_POINT_LEFT_CENTER, .parent = CLAY_ATTACH_POINT_RIGHT_CENTER }, .attachTo = CLAY_ATTACH_TO_ROOT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT },
3548          .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = { .bottom = 1 } }
3549      }) {
3550          CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_2 }) {
3551              CLAY_TEXT(CLAY_STRING("Clay Debug Tools"), infoTextConfig);
3552              CLAY_AUTO_ID({ .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) } } }) {}
3553              // Close button
3554              CLAY_AUTO_ID({
3555                  .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} },
3556                  .backgroundColor = {217,91,67,80},
3557                  .cornerRadius = CLAY_CORNER_RADIUS(4),
3558                  .border = { .color = { 217,91,67,255 }, .width = { 1, 1, 1, 1, 0 } },
3559              }) {
3560                  Clay_OnHover(HandleDebugViewCloseButtonInteraction, 0);
3561                  CLAY_TEXT(CLAY_STRING("x"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3562              }
3563          }
3564          CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(1)} }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_3 } ) {}
3565          CLAY(scrollId, { .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() } }) {
3566              CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 }) {
3567                  Clay_ElementId panelContentsId = Clay__HashString(CLAY_STRING("Clay__DebugViewPaneOuter"), 0);
3568                  // Element list
3569                  CLAY(panelContentsId, { .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .floating = { .zIndex = 32766, .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH, .attachTo = CLAY_ATTACH_TO_PARENT, .clipTo = CLAY_CLIP_TO_ATTACHED_PARENT } }) {
3570                      CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .padding = { CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3571                          layoutData = Clay__RenderDebugLayoutElementsList((int32_t)initialRootsLength, highlightedRow);
3572                      }
3573                  }
3574                  float contentWidth = Clay__GetHashMapItem(panelContentsId.id)->layoutElement->dimensions.width;
3575                  CLAY_AUTO_ID({ .layout = { .sizing = {.width = CLAY_SIZING_FIXED(contentWidth) }, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {}
3576                  for (int32_t i = 0; i < layoutData.rowCount; i++) {
3577                      Clay_Color rowColor = (i & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1;
3578                      if (i == layoutData.selectedElementRowIndex) {
3579                          rowColor = CLAY__DEBUGVIEW_COLOR_SELECTED_ROW;
3580                      }
3581                      if (i == highlightedRow) {
3582                          rowColor.r *= 1.25f;
3583                          rowColor.g *= 1.25f;
3584                          rowColor.b *= 1.25f;
3585                      }
3586                      CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = rowColor } ) {}
3587                  }
3588              }
3589          }
3590          CLAY_AUTO_ID({ .layout = { .sizing = {.width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(1)} }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_3 }) {}
3591          if (context->debugSelectedElementId != 0) {
3592              Clay_LayoutElementHashMapItem *selectedItem = Clay__GetHashMapItem(context->debugSelectedElementId);
3593              CLAY_AUTO_ID({
3594                  .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM },
3595                  .backgroundColor = CLAY__DEBUGVIEW_COLOR_2 ,
3596                  .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() },
3597                  .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = { .betweenChildren = 1 } }
3598              }) {
3599                  CLAY_AUTO_ID({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) {
3600                      CLAY_TEXT(CLAY_STRING("Element Configuration"), infoTextConfig);
3601                      CLAY_AUTO_ID({ .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) } } }) {}
3602                      if (selectedItem->elementId.stringId.length != 0) {
3603                          CLAY_TEXT(selectedItem->elementId.stringId, infoTitleConfig);
3604                          if (selectedItem->elementId.offset != 0) {
3605                              CLAY_TEXT(CLAY_STRING(" ("), infoTitleConfig);
3606                              CLAY_TEXT(Clay__IntToString(selectedItem->elementId.offset), infoTitleConfig);
3607                              CLAY_TEXT(CLAY_STRING(")"), infoTitleConfig);
3608                          }
3609                      }
3610                  }
3611                  Clay_Padding attributeConfigPadding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 8, 8};
3612                  // Clay_LayoutConfig debug info
3613                  CLAY_AUTO_ID({ .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3614                      CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 } }, .backgroundColor = { 200, 200, 200, 120 }, .cornerRadius = CLAY_CORNER_RADIUS(4), .border = { .color = { 200, 200, 200, 255 }, .width = { 1, 1, 1, 1, 0 } } }) {
3615                          CLAY_TEXT(CLAY_STRING("Layout"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3616                      }
3617                      // .boundingBox
3618                      CLAY_TEXT(CLAY_STRING("Bounding Box"), infoTitleConfig);
3619                      CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3620                          CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
3621                          CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.x), infoTextConfig);
3622                          CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig);
3623                          CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.y), infoTextConfig);
3624                          CLAY_TEXT(CLAY_STRING(", width: "), infoTextConfig);
3625                          CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.width), infoTextConfig);
3626                          CLAY_TEXT(CLAY_STRING(", height: "), infoTextConfig);
3627                          CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.height), infoTextConfig);
3628                          CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3629                      }
3630                      if (!selectedItem->layoutElement->isTextElement) {
3631                          // .layoutDirection
3632                          CLAY_TEXT(CLAY_STRING("Layout Direction"), infoTitleConfig);
3633                          Clay_LayoutConfig *layoutConfig = &selectedItem->layoutElement->config.layout;
3634                          CLAY_TEXT(layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM ? CLAY_STRING("TOP_TO_BOTTOM") : CLAY_STRING("LEFT_TO_RIGHT"), infoTextConfig);
3635                          // .sizing
3636                          CLAY_TEXT(CLAY_STRING("Sizing"), infoTitleConfig);
3637                          CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3638                              CLAY_TEXT(CLAY_STRING("width: "), infoTextConfig);
3639                              Clay__RenderDebugLayoutSizing(layoutConfig->sizing.width, infoTextConfig);
3640                          }
3641                          CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3642                              CLAY_TEXT(CLAY_STRING("height: "), infoTextConfig);
3643                              Clay__RenderDebugLayoutSizing(layoutConfig->sizing.height, infoTextConfig);
3644                          }
3645                          // .padding
3646                          CLAY_TEXT(CLAY_STRING("Padding"), infoTitleConfig);
3647                          CLAY(CLAY_ID("Clay__DebugViewElementInfoPadding"), { }) {
3648                              CLAY_TEXT(CLAY_STRING("{ left: "), infoTextConfig);
3649                              CLAY_TEXT(Clay__IntToString(layoutConfig->padding.left), infoTextConfig);
3650                              CLAY_TEXT(CLAY_STRING(", right: "), infoTextConfig);
3651                              CLAY_TEXT(Clay__IntToString(layoutConfig->padding.right), infoTextConfig);
3652                              CLAY_TEXT(CLAY_STRING(", top: "), infoTextConfig);
3653                              CLAY_TEXT(Clay__IntToString(layoutConfig->padding.top), infoTextConfig);
3654                              CLAY_TEXT(CLAY_STRING(", bottom: "), infoTextConfig);
3655                              CLAY_TEXT(Clay__IntToString(layoutConfig->padding.bottom), infoTextConfig);
3656                              CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3657                          }
3658                          // .childGap
3659                          CLAY_TEXT(CLAY_STRING("Child Gap"), infoTitleConfig);
3660                          CLAY_TEXT(Clay__IntToString(layoutConfig->childGap), infoTextConfig);
3661                          // .childAlignment
3662                          CLAY_TEXT(CLAY_STRING("Child Alignment"), infoTitleConfig);
3663                          CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3664                              CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
3665                              Clay_String alignX = CLAY_STRING("LEFT");
3666                              if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_CENTER) {
3667                                  alignX = CLAY_STRING("CENTER");
3668                              } else if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_RIGHT) {
3669                                  alignX = CLAY_STRING("RIGHT");
3670                              }
3671                              CLAY_TEXT(alignX, infoTextConfig);
3672                              CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig);
3673                              Clay_String alignY = CLAY_STRING("TOP");
3674                              if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_CENTER) {
3675                                  alignY = CLAY_STRING("CENTER");
3676                              } else if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_BOTTOM) {
3677                                  alignY = CLAY_STRING("BOTTOM");
3678                              }
3679                              CLAY_TEXT(alignY, infoTextConfig);
3680                              CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3681                          }
3682                      }
3683                  }
3684                  if (selectedItem->layoutElement->isTextElement) {
3685                      Clay_TextElementConfig *textConfig = &selectedItem->layoutElement->textConfig;
3686                      CLAY_AUTO_ID({ .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3687                          Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_TEXT);
3688                          // .fontSize
3689                          CLAY_TEXT(CLAY_STRING("Font Size"), infoTitleConfig);
3690                          CLAY_TEXT(Clay__IntToString(textConfig->fontSize), infoTextConfig);
3691                          // .fontId
3692                          CLAY_TEXT(CLAY_STRING("Font ID"), infoTitleConfig);
3693                          CLAY_TEXT(Clay__IntToString(textConfig->fontId), infoTextConfig);
3694                          // .lineHeight
3695                          CLAY_TEXT(CLAY_STRING("Line Height"), infoTitleConfig);
3696                          CLAY_TEXT(textConfig->lineHeight == 0 ? CLAY_STRING("auto") : Clay__IntToString(textConfig->lineHeight), infoTextConfig);
3697                          // .letterSpacing
3698                          CLAY_TEXT(CLAY_STRING("Letter Spacing"), infoTitleConfig);
3699                          CLAY_TEXT(Clay__IntToString(textConfig->letterSpacing), infoTextConfig);
3700                          // .wrapMode
3701                          CLAY_TEXT(CLAY_STRING("Wrap Mode"), infoTitleConfig);
3702                          Clay_String wrapMode = CLAY_STRING("WORDS");
3703                          if (textConfig->wrapMode == CLAY_TEXT_WRAP_NONE) {
3704                              wrapMode = CLAY_STRING("NONE");
3705                          } else if (textConfig->wrapMode == CLAY_TEXT_WRAP_NEWLINES) {
3706                              wrapMode = CLAY_STRING("NEWLINES");
3707                          }
3708                          CLAY_TEXT(wrapMode, infoTextConfig);
3709                          // .textAlignment
3710                          CLAY_TEXT(CLAY_STRING("Text Alignment"), infoTitleConfig);
3711                          Clay_String textAlignment = CLAY_STRING("LEFT");
3712                          if (textConfig->textAlignment == CLAY_TEXT_ALIGN_CENTER) {
3713                              textAlignment = CLAY_STRING("CENTER");
3714                          } else if (textConfig->textAlignment == CLAY_TEXT_ALIGN_RIGHT) {
3715                              textAlignment = CLAY_STRING("RIGHT");
3716                          }
3717                          CLAY_TEXT(textAlignment, infoTextConfig);
3718                          // .textColor
3719                          CLAY_TEXT(CLAY_STRING("Text Color"), infoTitleConfig);
3720                          Clay__RenderDebugViewColor(textConfig->textColor, infoTextConfig);
3721                      }
3722                  } else {
3723                      CLAY(CLAY_ID("Clay__DebugViewElementInfoSharedBody"), { .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3724                          Clay__DebugElementConfigTypeLabelConfig labelConfig = Clay__DebugGetElementConfigTypeLabel(CLAY__ELEMENT_CONFIG_TYPE_BACKGROUND_COLOR);
3725                          Clay_Color backgroundColor = labelConfig.color;
3726                          backgroundColor.a = 90;
3727                          CLAY_AUTO_ID({ .layout = { .padding = { 8, 8, 2, 2 } }, .backgroundColor = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4), .border = { .color = labelConfig.color, .width = { 1, 1, 1, 1, 0 } } }) {
3728                              CLAY_TEXT(CLAY_STRING("Color & Radius"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
3729                          }
3730                          // .backgroundColor
3731                          if (selectedItem->layoutElement->config.backgroundColor.a > 0) {
3732                              CLAY_TEXT(CLAY_STRING("Background Color"), infoTitleConfig);
3733                              Clay__RenderDebugViewColor(selectedItem->layoutElement->config.backgroundColor, infoTextConfig);
3734                          }
3735                          // .cornerRadius
3736                          if (!Clay__MemCmp((const char*)&selectedItem->layoutElement->config.cornerRadius, (const char*)&Clay__CornerRadius_DEFAULT, sizeof(Clay_CornerRadius))) {
3737                              CLAY_TEXT(CLAY_STRING("Corner Radius"), infoTitleConfig);
3738                              Clay__RenderDebugViewCornerRadius(selectedItem->layoutElement->config.cornerRadius, infoTextConfig);
3739                          }
3740                          // .overlayColor
3741                          if (selectedItem->layoutElement->config.overlayColor.a > 0) {
3742                              CLAY_TEXT(CLAY_STRING("Overlay Color"), infoTitleConfig);
3743                              Clay__RenderDebugViewColor(selectedItem->layoutElement->config.overlayColor, infoTextConfig);
3744                          }
3745                      }
3746                      if (selectedItem->layoutElement->config.aspectRatio.aspectRatio > 0) {
3747                          Clay_AspectRatioElementConfig *aspectRatioConfig = &selectedItem->layoutElement->config.aspectRatio;
3748                          CLAY(CLAY_ID("Clay__DebugViewElementInfoAspectRatioBody"), { .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3749                              Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_ASPECT);
3750                              CLAY_TEXT(CLAY_STRING("Aspect Ratio"), infoTitleConfig);
3751                              // Aspect Ratio
3752                              CLAY(CLAY_ID("Clay__DebugViewElementInfoAspectRatio"), { }) {
3753                                  CLAY_TEXT(Clay__IntToString(aspectRatioConfig->aspectRatio), infoTextConfig);
3754                                  CLAY_TEXT(CLAY_STRING("."), infoTextConfig);
3755                                  float frac = aspectRatioConfig->aspectRatio - (int)(aspectRatioConfig->aspectRatio);
3756                                  frac *= 100;
3757                                  if ((int)frac < 10) {
3758                                      CLAY_TEXT(CLAY_STRING("0"), infoTextConfig);
3759                                  }
3760                                  CLAY_TEXT(Clay__IntToString(frac), infoTextConfig);
3761                              }
3762                          }
3763                      }
3764                      if (selectedItem->layoutElement->config.image.imageData) {
3765                          Clay_ImageElementConfig *imageConfig = &selectedItem->layoutElement->config.image;
3766                          Clay_AspectRatioElementConfig aspectConfig = { 1 };
3767                          if (selectedItem->layoutElement->config.aspectRatio.aspectRatio > 0) {
3768                              aspectConfig = selectedItem->layoutElement->config.aspectRatio;
3769                          }
3770                          CLAY(CLAY_ID("Clay__DebugViewElementInfoImageBody"), { .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3771                              Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_IMAGE);
3772                              // Image Preview
3773                              CLAY_TEXT(CLAY_STRING("Preview"), infoTitleConfig);
3774                              CLAY_AUTO_ID({ .layout = { .sizing = { .width = CLAY_SIZING_GROW(64, 128), .height = CLAY_SIZING_GROW(64, 128) }}, .aspectRatio = aspectConfig, .image = *imageConfig }) {}
3775                          }
3776                      }
3777                      if (selectedItem->layoutElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
3778                          Clay_FloatingElementConfig* floatingConfig = &selectedItem->layoutElement->config.floating;
3779                          CLAY_AUTO_ID({ .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3780                              Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_FLOATING);
3781                              // .offset
3782                              CLAY_TEXT(CLAY_STRING("Offset"), infoTitleConfig);
3783                              CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3784                                  CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
3785                                  CLAY_TEXT(Clay__IntToString(floatingConfig->offset.x), infoTextConfig);
3786                                  CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig);
3787                                  CLAY_TEXT(Clay__IntToString(floatingConfig->offset.y), infoTextConfig);
3788                                  CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3789                              }
3790                              // .expand
3791                              CLAY_TEXT(CLAY_STRING("Expand"), infoTitleConfig);
3792                              CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3793                                  CLAY_TEXT(CLAY_STRING("{ width: "), infoTextConfig);
3794                                  CLAY_TEXT(Clay__IntToString(floatingConfig->expand.width), infoTextConfig);
3795                                  CLAY_TEXT(CLAY_STRING(", height: "), infoTextConfig);
3796                                  CLAY_TEXT(Clay__IntToString(floatingConfig->expand.height), infoTextConfig);
3797                                  CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3798                              }
3799                              // .zIndex
3800                              CLAY_TEXT(CLAY_STRING("z-index"), infoTitleConfig);
3801                              CLAY_TEXT(Clay__IntToString(floatingConfig->zIndex), infoTextConfig);
3802                              // .parentId
3803                              CLAY_TEXT(CLAY_STRING("Parent"), infoTitleConfig);
3804                              Clay_LayoutElementHashMapItem *hashItem = Clay__GetHashMapItem(floatingConfig->parentId);
3805                              CLAY_TEXT(hashItem->elementId.stringId, infoTextConfig);
3806                              // .attachPoints
3807                              CLAY_TEXT(CLAY_STRING("Attach Points"), infoTitleConfig);
3808                              CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3809                                  CLAY_TEXT(CLAY_STRING("{ element: "), infoTextConfig);
3810                                  Clay_String attachPointElement = CLAY_STRING("LEFT_TOP");
3811                                  if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_LEFT_CENTER) {
3812                                      attachPointElement = CLAY_STRING("LEFT_CENTER");
3813                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_LEFT_BOTTOM) {
3814                                      attachPointElement = CLAY_STRING("LEFT_BOTTOM");
3815                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_CENTER_TOP) {
3816                                      attachPointElement = CLAY_STRING("CENTER_TOP");
3817                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_CENTER_CENTER) {
3818                                      attachPointElement = CLAY_STRING("CENTER_CENTER");
3819                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_CENTER_BOTTOM) {
3820                                      attachPointElement = CLAY_STRING("CENTER_BOTTOM");
3821                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_RIGHT_TOP) {
3822                                      attachPointElement = CLAY_STRING("RIGHT_TOP");
3823                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_RIGHT_CENTER) {
3824                                      attachPointElement = CLAY_STRING("RIGHT_CENTER");
3825                                  } else if (floatingConfig->attachPoints.element == CLAY_ATTACH_POINT_RIGHT_BOTTOM) {
3826                                      attachPointElement = CLAY_STRING("RIGHT_BOTTOM");
3827                                  }
3828                                  CLAY_TEXT(attachPointElement, infoTextConfig);
3829                                  Clay_String attachPointParent = CLAY_STRING("LEFT_TOP");
3830                                  if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_LEFT_CENTER) {
3831                                      attachPointParent = CLAY_STRING("LEFT_CENTER");
3832                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_LEFT_BOTTOM) {
3833                                      attachPointParent = CLAY_STRING("LEFT_BOTTOM");
3834                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_CENTER_TOP) {
3835                                      attachPointParent = CLAY_STRING("CENTER_TOP");
3836                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_CENTER_CENTER) {
3837                                      attachPointParent = CLAY_STRING("CENTER_CENTER");
3838                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_CENTER_BOTTOM) {
3839                                      attachPointParent = CLAY_STRING("CENTER_BOTTOM");
3840                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_RIGHT_TOP) {
3841                                      attachPointParent = CLAY_STRING("RIGHT_TOP");
3842                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_RIGHT_CENTER) {
3843                                      attachPointParent = CLAY_STRING("RIGHT_CENTER");
3844                                  } else if (floatingConfig->attachPoints.parent == CLAY_ATTACH_POINT_RIGHT_BOTTOM) {
3845                                      attachPointParent = CLAY_STRING("RIGHT_BOTTOM");
3846                                  }
3847                                  CLAY_TEXT(CLAY_STRING(", parent: "), infoTextConfig);
3848                                  CLAY_TEXT(attachPointParent, infoTextConfig);
3849                                  CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3850                              }
3851                              // .pointerCaptureMode
3852                              CLAY_TEXT(CLAY_STRING("Pointer Capture Mode"), infoTitleConfig);
3853                              Clay_String pointerCaptureMode = CLAY_STRING("NONE");
3854                              if (floatingConfig->pointerCaptureMode == CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH) {
3855                                  pointerCaptureMode = CLAY_STRING("PASSTHROUGH");
3856                              }
3857                              CLAY_TEXT(pointerCaptureMode, infoTextConfig);
3858                              // .attachTo
3859                              CLAY_TEXT(CLAY_STRING("Attach To"), infoTitleConfig);
3860                              Clay_String attachTo = CLAY_STRING("NONE");
3861                              if (floatingConfig->attachTo == CLAY_ATTACH_TO_PARENT) {
3862                                  attachTo = CLAY_STRING("PARENT");
3863                              } else if (floatingConfig->attachTo == CLAY_ATTACH_TO_ELEMENT_WITH_ID) {
3864                                  attachTo = CLAY_STRING("ELEMENT_WITH_ID");
3865                              } else if (floatingConfig->attachTo == CLAY_ATTACH_TO_ROOT) {
3866                                  attachTo = CLAY_STRING("ROOT");
3867                              }
3868                              CLAY_TEXT(attachTo, infoTextConfig);
3869                              // .clipTo
3870                              CLAY_TEXT(CLAY_STRING("Clip To"), infoTitleConfig);
3871                              Clay_String clipTo = CLAY_STRING("ATTACHED_PARENT");
3872                              if (floatingConfig->clipTo == CLAY_CLIP_TO_NONE) {
3873                                  clipTo = CLAY_STRING("NONE");
3874                              }
3875                              CLAY_TEXT(clipTo, infoTextConfig);
3876                          }
3877                      }
3878                      Clay_ClipElementConfig *clipConfig = &selectedItem->layoutElement->config.clip;
3879                      if (clipConfig->horizontal || clipConfig->vertical) {
3880                          CLAY_AUTO_ID({ .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3881                              Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_CLIP);
3882                              // .vertical
3883                              CLAY_TEXT(CLAY_STRING("Vertical"), infoTitleConfig);
3884                              CLAY_TEXT(clipConfig->vertical ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig);
3885                              // .horizontal
3886                              CLAY_TEXT(CLAY_STRING("Horizontal"), infoTitleConfig);
3887                              CLAY_TEXT(clipConfig->horizontal ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig);
3888                          }
3889                      }
3890                      Clay_BorderElementConfig *borderConfig = &selectedItem->layoutElement->config.border;
3891                      if (Clay__BorderHasAnyWidth(borderConfig)) {
3892                          CLAY(CLAY_ID("Clay__DebugViewElementInfoBorderBody"), { .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
3893                              Clay__DebugViewRenderElementConfigHeader(selectedItem->elementId.stringId, CLAY__ELEMENT_CONFIG_TYPE_BORDER);
3894                              CLAY_TEXT(CLAY_STRING("Border Widths"), infoTitleConfig);
3895                              CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) {
3896                                  CLAY_TEXT(CLAY_STRING("{ left: "), infoTextConfig);
3897                                  CLAY_TEXT(Clay__IntToString(borderConfig->width.left), infoTextConfig);
3898                                  CLAY_TEXT(CLAY_STRING(", right: "), infoTextConfig);
3899                                  CLAY_TEXT(Clay__IntToString(borderConfig->width.right), infoTextConfig);
3900                                  CLAY_TEXT(CLAY_STRING(", top: "), infoTextConfig);
3901                                  CLAY_TEXT(Clay__IntToString(borderConfig->width.top), infoTextConfig);
3902                                  CLAY_TEXT(CLAY_STRING(", bottom: "), infoTextConfig);
3903                                  CLAY_TEXT(Clay__IntToString(borderConfig->width.bottom), infoTextConfig);
3904                                  CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
3905                              }
3906                              // .textColor
3907                              CLAY_TEXT(CLAY_STRING("Border Color"), infoTitleConfig);
3908                              Clay__RenderDebugViewColor(borderConfig->color, infoTextConfig);
3909                          }
3910                      }
3911                  }
3912              }
3913          } else {
3914              CLAY(CLAY_ID("Clay__DebugViewWarningsScrollPane"), { .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_2, .clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() } }) {
3915                  Clay_TextElementConfig warningConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE });
3916                  CLAY(CLAY_ID("Clay__DebugViewWarningItemHeader"), { .layout = { .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) {
3917                      CLAY_TEXT(CLAY_STRING("Warnings"), warningConfig);
3918                  }
3919                  CLAY(CLAY_ID("Clay__DebugViewWarningsTopBorder"), { .layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(1)} }, .backgroundColor = {200, 200, 200, 255} }) {}
3920                  int32_t previousWarningsLength = context->warnings.length;
3921                  for (int32_t i = 0; i < previousWarningsLength; i++) {
3922                      Clay__Warning warning = context->warnings.internalArray[i];
3923                      CLAY(CLAY_IDI("Clay__DebugViewWarningItem", i), { .layout = { .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) {
3924                          CLAY_TEXT(warning.baseMessage, warningConfig);
3925                          if (warning.dynamicMessage.length > 0) {
3926                              CLAY_TEXT(warning.dynamicMessage, warningConfig);
3927                          }
3928                      }
3929                  }
3930              }
3931          }
3932      }
3933  }
3934  #pragma endregion
3935  
3936  uint32_t Clay__debugViewWidth = 400;
3937  Clay_Color Clay__debugViewHighlightColor = { 168, 66, 28, 100 };
3938  
3939  Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Arena *arena) {
3940      size_t totalSizeBytes = capacity * sizeof(Clay_String);
3941      Clay__WarningArray array = {.capacity = capacity, .length = 0};
3942      uintptr_t nextAllocOffset = arena->nextAllocation + (64 - (arena->nextAllocation % 64));
3943      if (nextAllocOffset + totalSizeBytes <= arena->capacity) {
3944          array.internalArray = (Clay__Warning*)((uintptr_t)arena->memory + (uintptr_t)nextAllocOffset);
3945          arena->nextAllocation = nextAllocOffset + totalSizeBytes;
3946      }
3947      else {
3948          Clay__currentContext->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
3949              .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
3950              .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()"),
3951              .userData = Clay__currentContext->errorHandler.userData });
3952      }
3953      return array;
3954  }
3955  
3956  Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item)
3957  {
3958      if (array->length < array->capacity) {
3959          array->internalArray[array->length++] = item;
3960          return &array->internalArray[array->length - 1];
3961      }
3962      return &CLAY__WARNING_DEFAULT;
3963  }
3964  
3965  void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, Clay_Arena *arena)
3966  {
3967      size_t totalSizeBytes = capacity * itemSize;
3968      uintptr_t nextAllocOffset = arena->nextAllocation + ((64 - (arena->nextAllocation % 64)) & 63);
3969      if (nextAllocOffset + totalSizeBytes <= arena->capacity) {
3970          arena->nextAllocation = nextAllocOffset + totalSizeBytes;
3971          return (void*)((uintptr_t)arena->memory + (uintptr_t)nextAllocOffset);
3972      }
3973      else {
3974          Clay__currentContext->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
3975                  .errorType = CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED,
3976                  .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()"),
3977                  .userData = Clay__currentContext->errorHandler.userData });
3978      }
3979      return CLAY__NULL;
3980  }
3981  
3982  bool Clay__Array_RangeCheck(int32_t index, int32_t length)
3983  {
3984      if (index < length && index >= 0) {
3985          return true;
3986      }
3987      Clay_Context* context = Clay_GetCurrentContext();
3988      context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
3989              .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR,
3990              .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."),
3991              .userData = context->errorHandler.userData });
3992      return false;
3993  }
3994  
3995  bool Clay__Array_AddCapacityCheck(int32_t length, int32_t capacity)
3996  {
3997      if (length < capacity) {
3998          return true;
3999      }
4000      Clay_Context* context = Clay_GetCurrentContext();
4001      context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
4002          .errorType = CLAY_ERROR_TYPE_INTERNAL_ERROR,
4003          .errorText = CLAY_STRING("Clay attempted to make an out of bounds array access. This is an internal error and is likely a bug."),
4004          .userData = context->errorHandler.userData });
4005      return false;
4006  }
4007  
4008  // PUBLIC API FROM HERE ---------------------------------------
4009  
4010  CLAY_WASM_EXPORT("Clay_MinMemorySize")
4011  uint32_t Clay_MinMemorySize(void) {
4012      Clay_Context fakeContext = {
4013          .maxElementCount = Clay__defaultMaxElementCount,
4014          .maxMeasureTextCacheWordCount = Clay__defaultMaxMeasureTextWordCacheCount,
4015          .internalArena = {
4016              .capacity = SIZE_MAX,
4017              .memory = NULL,
4018          }
4019      };
4020      Clay_Context* currentContext = Clay_GetCurrentContext();
4021      if (currentContext) {
4022          fakeContext.maxElementCount = currentContext->maxElementCount;
4023          fakeContext.maxMeasureTextCacheWordCount = currentContext->maxMeasureTextCacheWordCount;
4024      }
4025      // Reserve space in the arena for the context, important for calculating min memory size correctly
4026      Clay__Context_Allocate_Arena(&fakeContext.internalArena);
4027      Clay__InitializePersistentMemory(&fakeContext);
4028      Clay__InitializeEphemeralMemory(&fakeContext);
4029      return (uint32_t)fakeContext.internalArena.nextAllocation + 128;
4030  }
4031  
4032  CLAY_WASM_EXPORT("Clay_CreateArenaWithCapacityAndMemory")
4033  Clay_Arena Clay_CreateArenaWithCapacityAndMemory(size_t capacity, void *memory) {
4034      Clay_Arena arena = {
4035          .capacity = capacity,
4036          .memory = (char *)memory
4037      };
4038      return arena;
4039  }
4040  
4041  #ifndef CLAY_WASM
4042  void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData) {
4043      Clay_Context* context = Clay_GetCurrentContext();
4044      Clay__MeasureText = measureTextFunction;
4045      context->measureTextUserData = userData;
4046  }
4047  void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData) {
4048      Clay_Context* context = Clay_GetCurrentContext();
4049      Clay__QueryScrollOffset = queryScrollOffsetFunction;
4050      context->queryScrollOffsetUserData = userData;
4051  }
4052  #endif
4053  
4054  CLAY_WASM_EXPORT("Clay_SetLayoutDimensions")
4055  void Clay_SetLayoutDimensions(Clay_Dimensions dimensions) {
4056      Clay_Context* context = Clay_GetCurrentContext();
4057      context->rootResizedLastFrame = !Clay__FloatEqual(context->layoutDimensions.width, dimensions.width) || !Clay__FloatEqual(context->layoutDimensions.height, dimensions.height);
4058      Clay_GetCurrentContext()->layoutDimensions = dimensions;
4059  }
4060  
4061  CLAY_WASM_EXPORT("Clay_SetPointerState")
4062  void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
4063      Clay_Context* context = Clay_GetCurrentContext();
4064      if (context->booleanWarnings.maxElementsExceeded) {
4065          return;
4066      }
4067      context->pointerInfo.position = position;
4068      context->pointerOverIds.length = 0;
4069      Clay__int32_tArray dfsBuffer = context->layoutElementChildrenBuffer;
4070      for (int32_t rootIndex = context->layoutElementTreeRoots.length - 1; rootIndex >= 0; --rootIndex) {
4071          dfsBuffer.length = 0;
4072          Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex);
4073          Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex);
4074          context->treeNodeVisited.internalArray[0] = false;
4075          bool found = false;
4076          bool skipTree = false;
4077          while (dfsBuffer.length > 0) {
4078              if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
4079                  dfsBuffer.length--;
4080                  continue;
4081              }
4082              context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
4083              Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&dfsBuffer, (int)dfsBuffer.length - 1));
4084              // Skip mouse interactions on an element if it's currently transitioning, based on user config
4085              if (currentElement->config.transition.handler) {
4086                  for (int I = 0; I < context->transitionDatas.length; ++I) {
4087                      Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, I);
4088                      if (data->elementId == currentElement->id) {
4089                          if (currentElement->config.transition.interactionHandling == CLAY_TRANSITION_DISABLE_INTERACTIONS_WHILE_TRANSITIONING_POSITION) {
4090                              if (data->state == CLAY_TRANSITION_STATE_EXITING || data->state == CLAY_TRANSITION_STATE_ENTERING || ((data->activeProperties & CLAY_TRANSITION_PROPERTY_POSITION) && data->state == CLAY_TRANSITION_STATE_TRANSITIONING)) {
4091                                  skipTree = true;
4092                              }
4093                          } else if (currentElement->config.transition.interactionHandling == CLAY_TRANSITION_ALLOW_INTERACTIONS_WHILE_TRANSITIONING_POSITION) {
4094                              if (data->state == CLAY_TRANSITION_STATE_EXITING) {
4095                                  skipTree = true;
4096                              }
4097                          }
4098                      }
4099                  }
4100              }
4101  
4102              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
4103              int32_t clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, (int32_t)(currentElement - context->layoutElements.internalArray));
4104              Clay_LayoutElementHashMapItem *clipItem = Clay__GetHashMapItem(clipElementId);
4105              if (mapItem && mapItem->generation > context->generation) {
4106                  Clay_BoundingBox elementBox = mapItem->boundingBox;
4107                  elementBox.x -= root->pointerOffset.x;
4108                  elementBox.y -= root->pointerOffset.y;
4109                  if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)) || context->externalScrollHandlingEnabled)) {
4110                      if (!skipTree) {
4111                          if (mapItem->onHoverFunction) {
4112                              mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData);
4113                          }
4114                          Clay_ElementIdArray_Add(&context->pointerOverIds, mapItem->elementId);
4115                      }
4116                      found = true;
4117                  }
4118                  if (skipTree || currentElement->isTextElement) {
4119                      dfsBuffer.length--;
4120                      continue;
4121                  }
4122                  for (int32_t i = currentElement->children.length - 1; i >= 0; --i) {
4123                      Clay__int32_tArray_Add(&dfsBuffer, currentElement->children.elements[i]);
4124                      context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked
4125                  }
4126              } else {
4127                  dfsBuffer.length--;
4128              }
4129          }
4130  
4131          Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, root->layoutElementIndex);
4132          if (found && rootElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE && rootElement->config.floating.pointerCaptureMode == CLAY_POINTER_CAPTURE_MODE_CAPTURE) {
4133              break;
4134          }
4135      }
4136  
4137      if (isPointerDown) {
4138          if (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
4139              context->pointerInfo.state = CLAY_POINTER_DATA_PRESSED;
4140          } else if (context->pointerInfo.state != CLAY_POINTER_DATA_PRESSED) {
4141              context->pointerInfo.state = CLAY_POINTER_DATA_PRESSED_THIS_FRAME;
4142          }
4143      } else {
4144          if (context->pointerInfo.state == CLAY_POINTER_DATA_RELEASED_THIS_FRAME) {
4145              context->pointerInfo.state = CLAY_POINTER_DATA_RELEASED;
4146          } else if (context->pointerInfo.state != CLAY_POINTER_DATA_RELEASED)  {
4147              context->pointerInfo.state = CLAY_POINTER_DATA_RELEASED_THIS_FRAME;
4148          }
4149      }
4150  }
4151  
4152  CLAY_WASM_EXPORT("Clay_GetPointerState")
4153  CLAY_DLL_EXPORT Clay_PointerData Clay_GetPointerState(void) {
4154      return Clay_GetCurrentContext()->pointerInfo;
4155  }
4156  
4157  CLAY_WASM_EXPORT("Clay_Initialize")
4158  Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) {
4159      // Cacheline align memory passed in
4160      uintptr_t baseOffset = 64 - ((uintptr_t)arena.memory % 64);
4161      baseOffset = baseOffset == 64 ? 0 : baseOffset;
4162      arena.memory += baseOffset;
4163      Clay_Context *context = Clay__Context_Allocate_Arena(&arena);
4164      if (context == NULL) return NULL;
4165      // DEFAULTS
4166      Clay_Context *oldContext = Clay_GetCurrentContext();
4167      *context = CLAY__INIT(Clay_Context) {
4168          .maxElementCount = oldContext ? oldContext->maxElementCount : Clay__defaultMaxElementCount,
4169          .maxMeasureTextCacheWordCount = oldContext ? oldContext->maxMeasureTextCacheWordCount : Clay__defaultMaxMeasureTextWordCacheCount,
4170          .errorHandler = errorHandler.errorHandlerFunction ? errorHandler : CLAY__INIT(Clay_ErrorHandler) { Clay__ErrorHandlerFunctionDefault, 0 },
4171          .layoutDimensions = layoutDimensions,
4172          .internalArena = arena,
4173      };
4174      Clay_SetCurrentContext(context);
4175      Clay__InitializePersistentMemory(context);
4176      Clay__InitializeEphemeralMemory(context);
4177      for (int32_t i = 0; i < context->layoutElementsHashMap.capacity; ++i) {
4178          context->layoutElementsHashMap.internalArray[i] = -1;
4179      }
4180      for (int32_t i = 0; i < context->measureTextHashMap.capacity; ++i) {
4181          context->measureTextHashMap.internalArray[i] = 0;
4182      }
4183      context->measureTextHashMapInternal.length = 1; // Reserve the 0 value to mean "no next element"
4184      context->layoutDimensions = layoutDimensions;
4185      return context;
4186  }
4187  
4188  CLAY_WASM_EXPORT("Clay_GetCurrentContext")
4189  Clay_Context* Clay_GetCurrentContext(void) {
4190      return Clay__currentContext;
4191  }
4192  
4193  CLAY_WASM_EXPORT("Clay_SetCurrentContext")
4194  void Clay_SetCurrentContext(Clay_Context* context) {
4195      Clay__currentContext = context;
4196  }
4197  
4198  CLAY_WASM_EXPORT("Clay_GetScrollOffset")
4199  Clay_Vector2 Clay_GetScrollOffset(void) {
4200      Clay_Context* context = Clay_GetCurrentContext();
4201      if (context->booleanWarnings.maxElementsExceeded) {
4202          return CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
4203      }
4204      Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
4205      for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) {
4206          Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
4207          if (mapping->layoutElement == openLayoutElement) {
4208              return mapping->scrollPosition;
4209          }
4210      }
4211      return CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
4212  }
4213  
4214  CLAY_WASM_EXPORT("Clay_UpdateScrollContainers")
4215  void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime) {
4216      Clay_Context* context = Clay_GetCurrentContext();
4217      bool isPointerActive = enableDragScrolling && (context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED || context->pointerInfo.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME);
4218      // Don't apply scroll events to ancestors of the inner element
4219      int32_t highestPriorityElementIndex = -1;
4220      Clay__ScrollContainerDataInternal *highestPriorityScrollData = CLAY__NULL;
4221      for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) {
4222          Clay__ScrollContainerDataInternal *scrollData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
4223          if (!scrollData->openThisFrame) {
4224              Clay__ScrollContainerDataInternalArray_RemoveSwapback(&context->scrollContainerDatas, i);
4225              continue;
4226          }
4227          scrollData->openThisFrame = false;
4228          Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(scrollData->elementId);
4229          // Element isn't rendered this frame but scroll offset has been retained
4230          if (!hashMapItem) {
4231              Clay__ScrollContainerDataInternalArray_RemoveSwapback(&context->scrollContainerDatas, i);
4232              continue;
4233          }
4234  
4235          // Touch / click is released
4236          if (!isPointerActive && scrollData->pointerScrollActive) {
4237              float xDiff = scrollData->scrollPosition.x - scrollData->scrollOrigin.x;
4238              if (xDiff < -10 || xDiff > 10) {
4239                  scrollData->scrollMomentum.x = (scrollData->scrollPosition.x - scrollData->scrollOrigin.x) / (scrollData->momentumTime * 25);
4240              }
4241              float yDiff = scrollData->scrollPosition.y - scrollData->scrollOrigin.y;
4242              if (yDiff < -10 || yDiff > 10) {
4243                  scrollData->scrollMomentum.y = (scrollData->scrollPosition.y - scrollData->scrollOrigin.y) / (scrollData->momentumTime * 25);
4244              }
4245              scrollData->pointerScrollActive = false;
4246  
4247              scrollData->pointerOrigin = CLAY__INIT(Clay_Vector2){0,0};
4248              scrollData->scrollOrigin = CLAY__INIT(Clay_Vector2){0,0};
4249              scrollData->momentumTime = 0;
4250          }
4251  
4252          // Apply existing momentum
4253          scrollData->scrollPosition.x += scrollData->scrollMomentum.x;
4254          scrollData->scrollMomentum.x *= 0.95f;
4255          bool scrollOccurred = scrollDelta.x != 0 || scrollDelta.y != 0;
4256          if ((scrollData->scrollMomentum.x > -0.1f && scrollData->scrollMomentum.x < 0.1f) || scrollOccurred) {
4257              scrollData->scrollMomentum.x = 0;
4258          }
4259          scrollData->scrollPosition.x = CLAY__MIN(CLAY__MAX(scrollData->scrollPosition.x, -(CLAY__MAX(scrollData->contentSize.width - scrollData->layoutElement->dimensions.width, 0))), 0);
4260  
4261          scrollData->scrollPosition.y += scrollData->scrollMomentum.y;
4262          scrollData->scrollMomentum.y *= 0.95f;
4263          if ((scrollData->scrollMomentum.y > -0.1f && scrollData->scrollMomentum.y < 0.1f) || scrollOccurred) {
4264              scrollData->scrollMomentum.y = 0;
4265          }
4266          scrollData->scrollPosition.y = CLAY__MIN(CLAY__MAX(scrollData->scrollPosition.y, -(CLAY__MAX(scrollData->contentSize.height - scrollData->layoutElement->dimensions.height, 0))), 0);
4267  
4268          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
4269              if (scrollData->layoutElement->id == Clay_ElementIdArray_Get(&context->pointerOverIds, j)->id) {
4270                  highestPriorityElementIndex = j;
4271                  highestPriorityScrollData = scrollData;
4272              }
4273          }
4274      }
4275  
4276      if (highestPriorityElementIndex > -1 && highestPriorityScrollData) {
4277          Clay_LayoutElement *scrollElement = highestPriorityScrollData->layoutElement;
4278          Clay_ClipElementConfig *clipConfig = &scrollElement->config.clip;
4279          bool canScrollVertically = clipConfig->vertical && highestPriorityScrollData->contentSize.height > scrollElement->dimensions.height;
4280          bool canScrollHorizontally = clipConfig->horizontal && highestPriorityScrollData->contentSize.width > scrollElement->dimensions.width;
4281          // Handle wheel scroll
4282          if (canScrollVertically) {
4283              highestPriorityScrollData->scrollPosition.y = highestPriorityScrollData->scrollPosition.y + scrollDelta.y * 10;
4284          }
4285          if (canScrollHorizontally) {
4286              highestPriorityScrollData->scrollPosition.x = highestPriorityScrollData->scrollPosition.x + scrollDelta.x * 10;
4287          }
4288          // Handle click / touch scroll
4289          if (isPointerActive) {
4290              highestPriorityScrollData->scrollMomentum = CLAY__INIT(Clay_Vector2)CLAY__DEFAULT_STRUCT;
4291              if (!highestPriorityScrollData->pointerScrollActive) {
4292                  highestPriorityScrollData->pointerOrigin = context->pointerInfo.position;
4293                  highestPriorityScrollData->scrollOrigin = highestPriorityScrollData->scrollPosition;
4294                  highestPriorityScrollData->pointerScrollActive = true;
4295              } else {
4296                  float scrollDeltaX = 0, scrollDeltaY = 0;
4297                  if (canScrollHorizontally) {
4298                      float oldXScrollPosition = highestPriorityScrollData->scrollPosition.x;
4299                      highestPriorityScrollData->scrollPosition.x = highestPriorityScrollData->scrollOrigin.x + (context->pointerInfo.position.x - highestPriorityScrollData->pointerOrigin.x);
4300                      highestPriorityScrollData->scrollPosition.x = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.x, 0), -(highestPriorityScrollData->contentSize.width - highestPriorityScrollData->boundingBox.width));
4301                      scrollDeltaX = highestPriorityScrollData->scrollPosition.x - oldXScrollPosition;
4302                  }
4303                  if (canScrollVertically) {
4304                      float oldYScrollPosition = highestPriorityScrollData->scrollPosition.y;
4305                      highestPriorityScrollData->scrollPosition.y = highestPriorityScrollData->scrollOrigin.y + (context->pointerInfo.position.y - highestPriorityScrollData->pointerOrigin.y);
4306                      highestPriorityScrollData->scrollPosition.y = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.y, 0), -(highestPriorityScrollData->contentSize.height - highestPriorityScrollData->boundingBox.height));
4307                      scrollDeltaY = highestPriorityScrollData->scrollPosition.y - oldYScrollPosition;
4308                  }
4309                  if (scrollDeltaX > -0.1f && scrollDeltaX < 0.1f && scrollDeltaY > -0.1f && scrollDeltaY < 0.1f && highestPriorityScrollData->momentumTime > 0.15f) {
4310                      highestPriorityScrollData->momentumTime = 0;
4311                      highestPriorityScrollData->pointerOrigin = context->pointerInfo.position;
4312                      highestPriorityScrollData->scrollOrigin = highestPriorityScrollData->scrollPosition;
4313                  } else {
4314                       highestPriorityScrollData->momentumTime += deltaTime;
4315                  }
4316              }
4317          }
4318          // Clamp any changes to scroll position to the maximum size of the contents
4319          if (canScrollVertically) {
4320              highestPriorityScrollData->scrollPosition.y = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.y, 0), -(highestPriorityScrollData->contentSize.height - scrollElement->dimensions.height));
4321          }
4322          if (canScrollHorizontally) {
4323              highestPriorityScrollData->scrollPosition.x = CLAY__MAX(CLAY__MIN(highestPriorityScrollData->scrollPosition.x, 0), -(highestPriorityScrollData->contentSize.width - scrollElement->dimensions.width));
4324          }
4325      }
4326  }
4327  
4328  CLAY_WASM_EXPORT("Clay_BeginLayout")
4329  void Clay_BeginLayout(void) {
4330      Clay_Context* context = Clay_GetCurrentContext();
4331      Clay__InitializeEphemeralMemory(context);
4332      context->generation++;
4333      context->dynamicElementIndex = 0;
4334      // Set up the root container that covers the entire window
4335      Clay_Dimensions rootDimensions = {context->layoutDimensions.width, context->layoutDimensions.height};
4336      if (context->debugModeEnabled) {
4337          rootDimensions.width -= (float)Clay__debugViewWidth;
4338      }
4339      context->booleanWarnings = CLAY__INIT(Clay_BooleanWarnings) CLAY__DEFAULT_STRUCT;
4340      Clay__OpenElementWithId(CLAY_ID("Clay__RootContainer"));
4341      Clay__ConfigureOpenElement(CLAY__INIT(Clay_ElementDeclaration) {
4342          .layout = { .sizing = {CLAY_SIZING_FIXED((rootDimensions.width)), CLAY_SIZING_FIXED(rootDimensions.height)} }
4343      });
4344      Clay__int32_tArray_Add(&context->openLayoutElementStack, 0);
4345      Clay__LayoutElementTreeRootArray_Add(&context->layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) { .layoutElementIndex = 0 });
4346  }
4347  
4348  void Clay__CloneElementsWithExitTransition() {
4349      Clay_Context* context = Clay_GetCurrentContext();
4350      int32_t nextIndex = context->layoutElements.capacity - 1;
4351      int32_t nextChildIndex = context->layoutElementChildren.capacity - 1;
4352  
4353      for (int i = 0; i < context->transitionDatas.length; ++i) {
4354          Clay__TransitionDataInternal *data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i);
4355          Clay_TransitionElementConfig* config = &data->elementThisFrame->config.transition;
4356          if (data->transitionOut) {
4357              Clay__int32_tArray bfsBuffer = context->openLayoutElementStack;
4358              bfsBuffer.length = 0;
4359              Clay_LayoutElement* newElement = Clay_LayoutElementArray_Set_DontTouchLength(&context->layoutElements, nextIndex, *data->elementThisFrame);
4360              Clay__StringArray_Set_DontTouchLength(&context->layoutElementIdStrings, nextIndex, *Clay__StringArray_GetCheckCapacity(&context->layoutElementIdStrings, data->elementThisFrame - context->layoutElements.internalArray));
4361              Clay__int32_tArray_Add(&bfsBuffer, nextIndex);
4362              data->elementThisFrame = newElement;
4363              nextIndex--;
4364  
4365              int32_t bufferIndex = 0;
4366              while(bufferIndex < bfsBuffer.length) {
4367                  Clay_LayoutElement *layoutElement = Clay_LayoutElementArray_GetCheckCapacity(&context->layoutElements, Clay__int32_tArray_GetValue(&bfsBuffer, bufferIndex));
4368                  bufferIndex++;
4369                  for (int j = layoutElement->children.length - 1; j >= 0; --j) {
4370                      Clay_LayoutElement* childElement = Clay_LayoutElementArray_GetCheckCapacity(&context->layoutElements, layoutElement->children.elements[j]);
4371                      Clay__int32_tArray_Add(&bfsBuffer, nextIndex);
4372                      Clay_LayoutElement* newChildElement = Clay_LayoutElementArray_Set_DontTouchLength(&context->layoutElements, nextIndex, *childElement);
4373                      Clay__StringArray_Set_DontTouchLength(&context->layoutElementIdStrings, nextIndex, *Clay__StringArray_GetCheckCapacity(&context->layoutElementIdStrings, childElement - context->layoutElements.internalArray));
4374                      Clay__int32_tArray_Set_DontTouchLength(&context->layoutElementChildren, nextChildIndex, nextIndex);
4375                      nextIndex--;
4376                      nextChildIndex--;
4377                  }
4378                  layoutElement->children.elements = &context->layoutElementChildren.internalArray[nextChildIndex + 1];
4379              }
4380          }
4381      }
4382  };
4383  
4384  void Clay_ApplyTransitionedPropertiesToElement(Clay_LayoutElement* currentElement, Clay_TransitionProperty properties, Clay_TransitionData currentTransitionData, Clay_BoundingBox* boundingBox, bool reparented) {
4385      if (properties & CLAY_TRANSITION_PROPERTY_WIDTH) {
4386          if (!reparented) {
4387              currentElement->dimensions.width = currentTransitionData.boundingBox.width;
4388              currentElement->config.layout.sizing.width = CLAY_SIZING_FIXED(currentTransitionData.boundingBox.width);
4389          } else {
4390              boundingBox->width = currentTransitionData.boundingBox.width;
4391          }
4392      }
4393      if (properties & CLAY_TRANSITION_PROPERTY_HEIGHT) {
4394          if (!reparented) {
4395              currentElement->dimensions.height = currentTransitionData.boundingBox.height;
4396              currentElement->config.layout.sizing.height = CLAY_SIZING_FIXED(currentTransitionData.boundingBox.height);
4397          } else {
4398              boundingBox->height = currentTransitionData.boundingBox.height;
4399          }
4400      }
4401      if (properties & CLAY_TRANSITION_PROPERTY_X) {
4402          boundingBox->x = currentTransitionData.boundingBox.x;
4403      }
4404      if (properties & CLAY_TRANSITION_PROPERTY_Y) {
4405          boundingBox->y = currentTransitionData.boundingBox.y;
4406      }
4407      if (properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) {
4408          currentElement->config.overlayColor = currentTransitionData.overlayColor;
4409      }
4410      if (properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) {
4411          currentElement->config.backgroundColor = currentTransitionData.backgroundColor;
4412      }
4413      if (properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) {
4414          currentElement->config.border.color = currentTransitionData.borderColor;
4415      }
4416      if (properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) {
4417          currentElement->config.border.width = currentTransitionData.borderWidth;
4418      }
4419  }
4420  
4421  void Clay__CreateDebugView() {
4422  
4423  }
4424  
4425  CLAY_WASM_EXPORT("Clay_EndLayout")
4426  Clay_RenderCommandArray Clay_EndLayout(float deltaTime) {
4427      Clay_Context* context = Clay_GetCurrentContext();
4428      Clay__CloseElement();
4429  
4430      for (int i = 0; i < context->transitionDatas.length; ++i) {
4431          Clay__TransitionDataInternal *data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i);
4432          Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(data->elementId);
4433          // This might seems strange - can't we just look up the element itself, and check the config to see whether it has an exit transition defined?
4434          // That would work fine if the element actually had an exit transition in the first place. If it doesn't have an exit transition defined, the element
4435          // will have simply disappeared completely at this point, and there will be no element through which to access the config.
4436          if (data->transitionOut) {
4437              Clay_TransitionElementConfig* config = &data->elementThisFrame->config.transition;
4438              // Element wasn't found this frame - either delete transition data or transition out
4439              if (hashMapItem->generation <= context->generation) {
4440                  Clay_LayoutElementHashMapItem *parentHashMapItem = Clay__GetHashMapItem(data->parentId);
4441                  // Don't exit transition if the parent has also exited and SKIP_WHEN_PARENT_EXITS is used
4442                  if (config->exit.trigger == CLAY_TRANSITION_EXIT_TRIGGER_WHEN_PARENT_EXITS || !parentHashMapItem || parentHashMapItem->generation > context->generation) {
4443                      if (data->state != CLAY_TRANSITION_STATE_EXITING) {
4444                          if (parentHashMapItem->generation <= context->generation) {
4445                              data->elementThisFrame->config.floating.attachTo = CLAY_ATTACH_TO_ROOT;
4446                              data->elementThisFrame->config.floating.offset = CLAY__INIT(Clay_Vector2) { hashMapItem->boundingBox.x, hashMapItem->boundingBox.y };
4447                          }
4448                          data->elementThisFrame->exiting = true;
4449                          data->elementThisFrame->config.layout.sizing.width = CLAY_SIZING_FIXED(data->elementThisFrame->dimensions.width);
4450                          data->elementThisFrame->config.layout.sizing.height = CLAY_SIZING_FIXED(data->elementThisFrame->dimensions.height);
4451                          data->state = CLAY_TRANSITION_STATE_EXITING;
4452                          data->activeProperties = config->properties;
4453                          data->elapsedTime = 0;
4454                          data->targetState = config->exit.setFinalState(data->targetState, config->properties);
4455                      }
4456  
4457                      // Clone the entire subtree back into the main UI layout tree
4458                      Clay__int32_tArray bfsBuffer = context->openLayoutElementStack;
4459                      bfsBuffer.length = 0;
4460                      data->elementThisFrame = Clay_LayoutElementArray_Add(&context->layoutElements, *data->elementThisFrame);
4461                      int32_t exitingElementIndex = data->elementThisFrame - context->layoutElements.internalArray;
4462                      Clay__StringArray_Add(&context->layoutElementIdStrings, *Clay__StringArray_GetCheckCapacity(&context->layoutElementIdStrings, exitingElementIndex));
4463                      Clay__int32_tArray_Add(&context->layoutElementClipElementIds, *Clay__int32_tArray_GetCheckCapacity(&context->layoutElementClipElementIds, exitingElementIndex));
4464                      Clay__int32_tArray_Add(&bfsBuffer, exitingElementIndex);
4465                      hashMapItem->layoutElement = data->elementThisFrame;
4466                      hashMapItem->generation = context->generation + 1;
4467                      int32_t bufferIndex = 0;
4468                      while (bufferIndex < bfsBuffer.length) {
4469                          Clay_LayoutElement *layoutElement = Clay_LayoutElementArray_GetCheckCapacity(&context->layoutElements, Clay__int32_tArray_GetValue(&bfsBuffer, bufferIndex));
4470                          bufferIndex++;
4471                          int32_t firstChildSlot = context->layoutElementChildren.length;
4472                          for (int j = 0; j < layoutElement->children.length; ++j) {
4473                              Clay_LayoutElement* childElement = Clay_LayoutElementArray_GetCheckCapacity(&context->layoutElements, layoutElement->children.elements[j]);
4474                              int32_t childElementIndex = childElement - context->layoutElements.internalArray;
4475                              Clay_LayoutElement* newChildElement = Clay_LayoutElementArray_Add(&context->layoutElements, *childElement);
4476                              Clay__StringArray_Add(&context->layoutElementIdStrings, *Clay__StringArray_GetCheckCapacity(&context->layoutElementIdStrings, childElementIndex));
4477                              Clay__int32_tArray_Add(&context->layoutElementClipElementIds, *Clay__int32_tArray_GetCheckCapacity(&context->layoutElementClipElementIds, childElementIndex));
4478                              Clay__int32_tArray_Add(&bfsBuffer, context->layoutElements.length - 1);
4479                              if (newChildElement->isTextElement) {
4480                                  newChildElement->textElementData.wrappedLines.length = 0;
4481                              }
4482                              Clay__int32_tArray_Add(&context->layoutElementChildren, context->layoutElements.length - 1);
4483                          }
4484                          layoutElement->children.elements = &context->layoutElementChildren.internalArray[firstChildSlot];
4485                      }
4486  
4487                      // Reattach the inserted subtree to its previous parent if it still exists
4488                      if (parentHashMapItem->generation > context->generation) {
4489                          Clay_LayoutElement *parentElement = parentHashMapItem->layoutElement;
4490                          int32_t newChildrenStartIndex = context->layoutElementChildren.length;
4491                          bool found = false;
4492                          if (config->exit.siblingOrdering == CLAY_EXIT_TRANSITION_ORDERING_UNDERNEATH_SIBLINGS) {
4493                              Clay__int32_tArray_Add(&context->layoutElementChildren, exitingElementIndex);
4494                              found = true;
4495                          }
4496                          for (int j = 0; j < parentElement->children.length; ++j) {
4497                              if (config->exit.siblingOrdering == CLAY_EXIT_TRANSITION_ORDERING_NATURAL_ORDER && j == data->siblingIndex) {
4498                                  Clay__int32_tArray_Add(&context->layoutElementChildren, exitingElementIndex);
4499                                  found = true;
4500                              }
4501                              Clay__int32_tArray_Add(&context->layoutElementChildren, parentElement->children.elements[j]);
4502                          }
4503                          if (!found) {
4504                              Clay__int32_tArray_Add(&context->layoutElementChildren, exitingElementIndex);
4505                          }
4506                          parentElement->children.length++;
4507                          parentElement->children.elements = &context->layoutElementChildren.internalArray[newChildrenStartIndex];
4508                      // Otherwise, just attach to the root as a floating element
4509                      } else {
4510                          Clay__LayoutElementTreeRootArray_Add(&context->layoutElementTreeRoots, CLAY__INIT(Clay__LayoutElementTreeRoot) {
4511                              .layoutElementIndex = (int32_t)(data->elementThisFrame - context->layoutElements.internalArray),
4512                              .parentId = Clay__HashString(CLAY_STRING("Clay__RootContainer"), 0).id,
4513                              .zIndex = 1,
4514                          });
4515                      }
4516                  // Parent exited, just delete child without exit transition
4517                  } else {
4518                      Clay__TransitionDataInternalArray_RemoveSwapback(&context->transitionDatas, i);
4519                      i--;
4520                      continue;
4521                  }
4522              }
4523          // Transition element exited and doesn't have an exit handler defined
4524          // Or, the user deleted the transition handler from one frame to the next
4525          } else if (hashMapItem->generation <= context->generation || !hashMapItem->layoutElement->config.transition.handler) {
4526              Clay__TransitionDataInternalArray_RemoveSwapback(&context->transitionDatas, i);
4527              i--;
4528              continue;
4529          }
4530      }
4531  
4532      if (context->booleanWarnings.maxElementsExceeded) {
4533          Clay_String message;
4534          message = CLAY_STRING("Clay Error: Layout elements exceeded Clay__maxElementCount");
4535          Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) {
4536              .boundingBox = { context->layoutDimensions.width / 2 - 59 * 4, context->layoutDimensions.height / 2, 0, 0 },
4537              .renderData = { .text = { .stringContents = CLAY__INIT(Clay_StringSlice) { .length = message.length, .chars = message.chars, .baseChars = message.chars }, .textColor = {255, 0, 0, 255}, .fontSize = 16 } },
4538              .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT
4539          });
4540      } else {
4541          if (context->transitionDatas.length > 0) {
4542              Clay__CalculateFinalLayout(deltaTime, false, false);
4543  
4544              for (int i = 0; i < context->transitionDatas.length; ++i) {
4545                  Clay__TransitionDataInternal* transitionData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i);
4546                  Clay_LayoutElement* currentElement = transitionData->elementThisFrame;
4547                  Clay_LayoutElementHashMapItem* mapItem = Clay__GetHashMapItem(transitionData->elementId);
4548                  Clay_LayoutElementHashMapItem* parentMapItem = Clay__GetHashMapItem(transitionData->parentId);
4549                  Clay_TransitionData targetState = transitionData->targetState;
4550                  if (transitionData->state != CLAY_TRANSITION_STATE_EXITING) {
4551                      targetState = CLAY__INIT(Clay_TransitionData) {
4552                              mapItem->boundingBox,
4553                              currentElement->config.backgroundColor,
4554                              currentElement->config.overlayColor,
4555                              currentElement->config.border.color,
4556                              currentElement->config.border.width,
4557                      };
4558                  }
4559                  Clay_TransitionData oldTargetState = transitionData->targetState;
4560                  transitionData->targetState = targetState;
4561                  if (mapItem->appearedThisFrame) {
4562                      if (currentElement->config.transition.enter.setInitialState && !(parentMapItem->appearedThisFrame && currentElement->config.transition.enter.trigger == CLAY_TRANSITION_ENTER_SKIP_ON_FIRST_PARENT_FRAME)) {
4563                          transitionData->state = CLAY_TRANSITION_STATE_ENTERING;
4564                          transitionData->initialState = currentElement->config.transition.enter.setInitialState(transitionData->targetState, currentElement->config.transition.properties);
4565                          transitionData->currentState = transitionData->initialState;
4566                          Clay_ApplyTransitionedPropertiesToElement(currentElement, currentElement->config.transition.properties, transitionData->initialState, &mapItem->boundingBox, transitionData->reparented);
4567                      } else {
4568                          transitionData->initialState = targetState;
4569                          transitionData->currentState = targetState;
4570                      }
4571                  } else {
4572                      Clay_Vector2 parentScrollOffset = parentMapItem->layoutElement->config.clip.childOffset;
4573                      Clay_Vector2 newRelativePosition = {
4574                          mapItem->boundingBox.x - parentMapItem->boundingBox.x - parentScrollOffset.x,
4575                          mapItem->boundingBox.y - parentMapItem->boundingBox.y - parentScrollOffset.y,
4576                      };
4577                      Clay_Vector2 oldRelativePosition = transitionData->oldParentRelativePosition;
4578                      transitionData->oldParentRelativePosition = newRelativePosition;
4579                      Clay_TransitionProperty properties = currentElement->config.transition.properties;
4580                      int32_t activeProperties = CLAY_TRANSITION_PROPERTY_NONE;
4581                      if (properties & CLAY_TRANSITION_PROPERTY_X) {
4582                          if (!Clay__FloatEqual(oldTargetState.boundingBox.x, targetState.boundingBox.x) && !(Clay__FloatEqual(oldRelativePosition.x, newRelativePosition.x)) && !context->rootResizedLastFrame) {
4583                              activeProperties |= CLAY_TRANSITION_PROPERTY_X;
4584                          }
4585                      }
4586                      if (properties & CLAY_TRANSITION_PROPERTY_Y) {
4587                          if (!Clay__FloatEqual(oldTargetState.boundingBox.y, targetState.boundingBox.y) && !(Clay__FloatEqual(oldRelativePosition.y, newRelativePosition.y)) && !context->rootResizedLastFrame) {
4588                              activeProperties |= CLAY_TRANSITION_PROPERTY_Y;
4589                          }
4590                      }
4591                      if (properties & CLAY_TRANSITION_PROPERTY_WIDTH) {
4592                          if (!Clay__FloatEqual(oldTargetState.boundingBox.width, targetState.boundingBox.width) && !context->rootResizedLastFrame) {
4593                              activeProperties |= CLAY_TRANSITION_PROPERTY_WIDTH;
4594                          }
4595                      }
4596                      if (properties & CLAY_TRANSITION_PROPERTY_HEIGHT) {
4597                          if (!Clay__FloatEqual(oldTargetState.boundingBox.height, targetState.boundingBox.height) && !context->rootResizedLastFrame) {
4598                              activeProperties |= CLAY_TRANSITION_PROPERTY_HEIGHT;
4599                          }
4600                      }
4601                      if (properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) {
4602                          if (!Clay__MemCmp((char *) &oldTargetState.backgroundColor, (char *)&targetState.backgroundColor, sizeof(Clay_Color))) {
4603                              activeProperties |= CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR;
4604                          }
4605                      }
4606                      if (properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) {
4607                          if (!Clay__MemCmp((char *) &oldTargetState.overlayColor, (char *)&targetState.overlayColor, sizeof(Clay_Color))) {
4608                              activeProperties |= CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR;
4609                          }
4610                      }
4611                      if (properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) {
4612                          if (!Clay__MemCmp((char *) &oldTargetState.borderColor, (char *)&targetState.borderColor, sizeof(Clay_Color))) {
4613                              activeProperties |= CLAY_TRANSITION_PROPERTY_BORDER_COLOR;
4614                          }
4615                      }
4616                      if (properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) {
4617                          if (!Clay__MemCmp((char *) &oldTargetState.borderWidth, (char *)&targetState.borderWidth, sizeof(Clay_BorderWidth))) {
4618                              activeProperties |= CLAY_TRANSITION_PROPERTY_BORDER_WIDTH;
4619                          }
4620                      }
4621  
4622                      if (activeProperties != 0 && transitionData->state != CLAY_TRANSITION_STATE_EXITING) {
4623                          transitionData->elapsedTime = 0;
4624                          transitionData->initialState = transitionData->currentState;
4625                          transitionData->state = CLAY_TRANSITION_STATE_TRANSITIONING;
4626                          transitionData->activeProperties = (Clay_TransitionProperty)activeProperties;
4627                      }
4628  
4629                      if (transitionData->state == CLAY_TRANSITION_STATE_IDLE) {
4630                          transitionData->initialState = targetState;
4631                          transitionData->currentState = targetState;
4632                          transitionData->targetState = targetState;
4633                      } else {
4634                          bool transitionComplete = true;
4635                          transitionComplete = currentElement->config.transition.handler(CLAY__INIT(Clay_TransitionCallbackArguments) {
4636                                  transitionData->state,
4637                                  transitionData->initialState,
4638                                  &transitionData->currentState,
4639                                  targetState,
4640                                  transitionData->elapsedTime,
4641                                  currentElement->config.transition.duration,
4642                                  currentElement->config.transition.properties
4643                          });
4644  
4645                          Clay_ApplyTransitionedPropertiesToElement(currentElement, currentElement->config.transition.properties, transitionData->currentState, &mapItem->boundingBox, transitionData->reparented);
4646                          transitionData->elapsedTime += deltaTime;
4647  
4648                          if (transitionComplete) {
4649                              if (transitionData->state == CLAY_TRANSITION_STATE_ENTERING || transitionData->state == CLAY_TRANSITION_STATE_TRANSITIONING) {transitionData->state = CLAY_TRANSITION_STATE_IDLE;
4650                                  transitionData->elapsedTime = 0;
4651                                  transitionData->reparented = false;
4652                                  transitionData->activeProperties = CLAY_TRANSITION_PROPERTY_NONE;
4653                              } else if (transitionData->state == CLAY_TRANSITION_STATE_EXITING) {
4654                                  Clay__TransitionDataInternalArray_RemoveSwapback(&context->transitionDatas, i);
4655                              }
4656                          }
4657                      }
4658                  }
4659              }
4660  
4661              if (context->debugModeEnabled) {
4662                  context->warningsEnabled = false;
4663                  Clay__RenderDebugView();
4664                  context->warningsEnabled = true;
4665              }
4666  
4667              if (context->booleanWarnings.maxElementsExceeded) {
4668                  Clay_String message;
4669                  message = CLAY_STRING("Clay Error: Debug view caused layout element count to exceed Clay__maxElementCount");
4670                  Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) {
4671                          .boundingBox = { context->layoutDimensions.width / 2 - 59 * 4, context->layoutDimensions.height / 2, 0, 0 },
4672                          .renderData = { .text = { .stringContents = CLAY__INIT(Clay_StringSlice) { .length = message.length, .chars = message.chars, .baseChars = message.chars }, .textColor = {255, 0, 0, 255}, .fontSize = 16 } },
4673                          .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT
4674                  });
4675              } else {
4676                  Clay__CalculateFinalLayout(deltaTime, true, true);
4677                  Clay__CloneElementsWithExitTransition();
4678              }
4679          } else {
4680              if (context->debugModeEnabled) {
4681                  context->warningsEnabled = false;
4682                  Clay__RenderDebugView();
4683                  context->warningsEnabled = true;
4684              }
4685  
4686              if (context->booleanWarnings.maxElementsExceeded) {
4687                  Clay_String message;
4688                  message = CLAY_STRING("Clay Error: Debug view caused layout element count to exceed Clay__maxElementCount");
4689                  Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand ) {
4690                      .boundingBox = { context->layoutDimensions.width / 2 - 59 * 4, context->layoutDimensions.height / 2, 0, 0 },
4691                      .renderData = { .text = { .stringContents = CLAY__INIT(Clay_StringSlice) { .length = message.length, .chars = message.chars, .baseChars = message.chars }, .textColor = {255, 0, 0, 255}, .fontSize = 16 } },
4692                      .commandType = CLAY_RENDER_COMMAND_TYPE_TEXT
4693                  });
4694              } else {
4695                  Clay__CalculateFinalLayout(deltaTime, false, true);
4696              }
4697          }
4698      }
4699      if (context->openLayoutElementStack.length > 1) {
4700          context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
4701                  .errorType = CLAY_ERROR_TYPE_UNBALANCED_OPEN_CLOSE,
4702                  .errorText = CLAY_STRING("There were still open layout elements when EndLayout was called. This results from an unequal number of calls to Clay__OpenElement and Clay__CloseElement."),
4703                  .userData = context->errorHandler.userData });
4704      }
4705      return context->renderCommands;
4706  }
4707  
4708  CLAY_WASM_EXPORT("Clay_GetOpenElementId")
4709  uint32_t Clay_GetOpenElementId(void) {
4710      return Clay__GetOpenLayoutElement()->id;
4711  }
4712  
4713  CLAY_WASM_EXPORT("Clay_GetElementId")
4714  Clay_ElementId Clay_GetElementId(Clay_String idString) {
4715      return Clay__HashString(idString, 0);
4716  }
4717  
4718  CLAY_WASM_EXPORT("Clay_GetElementIdWithIndex")
4719  Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index) {
4720      return Clay__HashStringWithOffset(idString, index, 0);
4721  }
4722  
4723  bool Clay_Hovered(void) {
4724      Clay_Context* context = Clay_GetCurrentContext();
4725      if (context->booleanWarnings.maxElementsExceeded) {
4726          return false;
4727      }
4728      Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
4729      for (int32_t i = 0; i < context->pointerOverIds.length; ++i) {
4730          if (Clay_ElementIdArray_Get(&context->pointerOverIds, i)->id == openLayoutElement->id) {
4731              return true;
4732          }
4733      }
4734      return false;
4735  }
4736  
4737  void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerInfo, void *userData), void *userData) {
4738      Clay_Context* context = Clay_GetCurrentContext();
4739      if (context->booleanWarnings.maxElementsExceeded) {
4740          return;
4741      }
4742      Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
4743      Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(openLayoutElement->id);
4744      hashMapItem->onHoverFunction = onHoverFunction;
4745      hashMapItem->hoverFunctionUserData = userData;
4746  }
4747  
4748  CLAY_WASM_EXPORT("Clay_PointerOver")
4749  bool Clay_PointerOver(Clay_ElementId elementId) { // TODO return priority for separating multiple results
4750      Clay_Context* context = Clay_GetCurrentContext();
4751      for (int32_t i = 0; i < context->pointerOverIds.length; ++i) {
4752          if (Clay_ElementIdArray_Get(&context->pointerOverIds, i)->id == elementId.id) {
4753              return true;
4754          }
4755      }
4756      return false;
4757  }
4758  
4759  CLAY_WASM_EXPORT("Clay_GetScrollContainerData")
4760  Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id) {
4761      Clay_Context* context = Clay_GetCurrentContext();
4762      for (int32_t i = 0; i < context->scrollContainerDatas.length; ++i) {
4763          Clay__ScrollContainerDataInternal *scrollContainerData = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
4764          if (scrollContainerData->elementId == id.id) {
4765              if (!scrollContainerData->layoutElement) { // This can happen on the first frame before a scroll container is declared
4766                  return CLAY__INIT(Clay_ScrollContainerData) CLAY__DEFAULT_STRUCT;
4767              }
4768              return CLAY__INIT(Clay_ScrollContainerData) {
4769                  .scrollPosition = &scrollContainerData->scrollPosition,
4770                  .scrollContainerDimensions = { scrollContainerData->boundingBox.width, scrollContainerData->boundingBox.height },
4771                  .contentDimensions = scrollContainerData->contentSize,
4772                  .config = scrollContainerData->layoutElement->config.clip,
4773                  .found = true
4774              };
4775          }
4776      }
4777      return CLAY__INIT(Clay_ScrollContainerData) CLAY__DEFAULT_STRUCT;
4778  }
4779  
4780  CLAY_WASM_EXPORT("Clay_GetElementData")
4781  Clay_ElementData Clay_GetElementData(Clay_ElementId id){
4782      Clay_LayoutElementHashMapItem * item = Clay__GetHashMapItem(id.id);
4783      if(item == &Clay_LayoutElementHashMapItem_DEFAULT) {
4784          return CLAY__INIT(Clay_ElementData) CLAY__DEFAULT_STRUCT;
4785      }
4786  
4787      return CLAY__INIT(Clay_ElementData){
4788          .boundingBox = item->boundingBox,
4789          .found = true
4790      };
4791  }
4792  
4793  CLAY_WASM_EXPORT("Clay_SetDebugModeEnabled")
4794  void Clay_SetDebugModeEnabled(bool enabled) {
4795      Clay_Context* context = Clay_GetCurrentContext();
4796      context->debugModeEnabled = enabled;
4797  }
4798  
4799  CLAY_WASM_EXPORT("Clay_IsDebugModeEnabled")
4800  bool Clay_IsDebugModeEnabled(void) {
4801      Clay_Context* context = Clay_GetCurrentContext();
4802      return context->debugModeEnabled;
4803  }
4804  
4805  CLAY_WASM_EXPORT("Clay_SetCullingEnabled")
4806  void Clay_SetCullingEnabled(bool enabled) {
4807      Clay_Context* context = Clay_GetCurrentContext();
4808      context->disableCulling = !enabled;
4809  }
4810  
4811  CLAY_WASM_EXPORT("Clay_SetExternalScrollHandlingEnabled")
4812  void Clay_SetExternalScrollHandlingEnabled(bool enabled) {
4813      Clay_Context* context = Clay_GetCurrentContext();
4814      context->externalScrollHandlingEnabled = enabled;
4815  }
4816  
4817  CLAY_WASM_EXPORT("Clay_GetMaxElementCount")
4818  int32_t Clay_GetMaxElementCount(void) {
4819      Clay_Context* context = Clay_GetCurrentContext();
4820      return context->maxElementCount;
4821  }
4822  
4823  CLAY_WASM_EXPORT("Clay_SetMaxElementCount")
4824  void Clay_SetMaxElementCount(int32_t maxElementCount) {
4825      Clay_Context* context = Clay_GetCurrentContext();
4826      if (context) {
4827          context->maxElementCount = maxElementCount;
4828      } else {
4829          Clay__defaultMaxElementCount = maxElementCount; // TODO: Fix this
4830          Clay__defaultMaxMeasureTextWordCacheCount = maxElementCount * 2;
4831      }
4832  }
4833  
4834  CLAY_WASM_EXPORT("Clay_GetMaxMeasureTextCacheWordCount")
4835  int32_t Clay_GetMaxMeasureTextCacheWordCount(void) {
4836      Clay_Context* context = Clay_GetCurrentContext();
4837      return context->maxMeasureTextCacheWordCount;
4838  }
4839  
4840  CLAY_WASM_EXPORT("Clay_SetMaxMeasureTextCacheWordCount")
4841  void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount) {
4842      Clay_Context* context = Clay_GetCurrentContext();
4843      if (context) {
4844          Clay__currentContext->maxMeasureTextCacheWordCount = maxMeasureTextCacheWordCount;
4845      } else {
4846          Clay__defaultMaxMeasureTextWordCacheCount = maxMeasureTextCacheWordCount; // TODO: Fix this
4847      }
4848  }
4849  
4850  CLAY_WASM_EXPORT("Clay_ResetMeasureTextCache")
4851  void Clay_ResetMeasureTextCache(void) {
4852      Clay_Context* context = Clay_GetCurrentContext();
4853      context->measureTextHashMapInternal.length = 0;
4854      context->measureTextHashMapInternalFreeList.length = 0;
4855      context->measureTextHashMap.length = 0;
4856      context->measuredWords.length = 0;
4857      context->measuredWordsFreeList.length = 0;
4858  
4859      for (int32_t i = 0; i < context->measureTextHashMap.capacity; ++i) {
4860          context->measureTextHashMap.internalArray[i] = 0;
4861      }
4862      context->measureTextHashMapInternal.length = 1; // Reserve the 0 value to mean "no next element"
4863  }
4864  
4865  #define CLAY__LERP(from, to, mix) (from + (to - from) * mix)
4866  
4867  CLAY_DLL_EXPORT bool Clay_EaseOut(Clay_TransitionCallbackArguments arguments) {
4868      float ratio = 1;
4869      if (arguments.duration > 0) {
4870          ratio = CLAY__MIN(arguments.elapsedTime / arguments.duration, 1);
4871      }
4872      float inverse = 1.0f - ratio;
4873      float lerpAmount = 1.0f - (inverse * inverse * inverse);
4874      if (arguments.properties & CLAY_TRANSITION_PROPERTY_X) {
4875          arguments.current->boundingBox.x = CLAY__LERP(arguments.initial.boundingBox.x, arguments.target.boundingBox.x, lerpAmount);
4876      }
4877      if (arguments.properties & CLAY_TRANSITION_PROPERTY_Y) {
4878          arguments.current->boundingBox.y = CLAY__LERP(arguments.initial.boundingBox.y, arguments.target.boundingBox.y, lerpAmount);
4879      }
4880      if (arguments.properties & CLAY_TRANSITION_PROPERTY_WIDTH) {
4881          arguments.current->boundingBox.width = CLAY__LERP(arguments.initial.boundingBox.width, arguments.target.boundingBox.width, lerpAmount);
4882      }
4883      if (arguments.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) {
4884          arguments.current->boundingBox.height = CLAY__LERP(arguments.initial.boundingBox.height, arguments.target.boundingBox.height, lerpAmount);
4885      }
4886      if (arguments.properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) {
4887          arguments.current->backgroundColor = CLAY__INIT(Clay_Color) {
4888              .r = CLAY__LERP(arguments.initial.backgroundColor.r, arguments.target.backgroundColor.r, lerpAmount),
4889              .g = CLAY__LERP(arguments.initial.backgroundColor.g, arguments.target.backgroundColor.g, lerpAmount),
4890              .b = CLAY__LERP(arguments.initial.backgroundColor.b, arguments.target.backgroundColor.b, lerpAmount),
4891              .a = CLAY__LERP(arguments.initial.backgroundColor.a, arguments.target.backgroundColor.a, lerpAmount),
4892          };
4893      }
4894      if (arguments.properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) {
4895          arguments.current->overlayColor = CLAY__INIT(Clay_Color) {
4896              .r = CLAY__LERP(arguments.initial.overlayColor.r, arguments.target.overlayColor.r, lerpAmount),
4897              .g = CLAY__LERP(arguments.initial.overlayColor.g, arguments.target.overlayColor.g, lerpAmount),
4898              .b = CLAY__LERP(arguments.initial.overlayColor.b, arguments.target.overlayColor.b, lerpAmount),
4899              .a = CLAY__LERP(arguments.initial.overlayColor.a, arguments.target.overlayColor.a, lerpAmount),
4900          };
4901      }
4902      if (arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) {
4903          arguments.current->borderColor = CLAY__INIT(Clay_Color) {
4904              .r = CLAY__LERP(arguments.initial.borderColor.r, arguments.target.borderColor.r, lerpAmount),
4905              .g = CLAY__LERP(arguments.initial.borderColor.g, arguments.target.borderColor.g, lerpAmount),
4906              .b = CLAY__LERP(arguments.initial.borderColor.b, arguments.target.borderColor.b, lerpAmount),
4907              .a = CLAY__LERP(arguments.initial.borderColor.a, arguments.target.borderColor.a, lerpAmount),
4908          };
4909      }
4910      if (arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) {
4911          arguments.current->borderWidth = CLAY__INIT(Clay_BorderWidth) {
4912              .left = (uint16_t)CLAY__LERP(arguments.initial.borderWidth.left, arguments.target.borderWidth.left, lerpAmount),
4913              .right = (uint16_t)CLAY__LERP(arguments.initial.borderWidth.right, arguments.target.borderWidth.right, lerpAmount),
4914              .top = (uint16_t)CLAY__LERP(arguments.initial.borderWidth.top, arguments.target.borderWidth.top, lerpAmount),
4915              .bottom = (uint16_t)CLAY__LERP(arguments.initial.borderWidth.bottom, arguments.target.borderWidth.bottom, lerpAmount),
4916              .betweenChildren = (uint16_t)CLAY__LERP(arguments.initial.borderWidth.betweenChildren, arguments.target.borderWidth.betweenChildren, lerpAmount),
4917          };
4918      }
4919      return ratio >= 1;
4920  }
4921  
4922  #endif // CLAY_IMPLEMENTATION
4923  
4924  /*
4925  LICENSE
4926  zlib/libpng license
4927  
4928  Copyright (c) 2024 Nic Barker
4929  
4930  This software is provided 'as-is', without any express or implied warranty.
4931  In no event will the authors be held liable for any damages arising from the
4932  use of this software.
4933  
4934  Permission is granted to anyone to use this software for any purpose,
4935  including commercial applications, and to alter it and redistribute it
4936  freely, subject to the following restrictions:
4937  
4938      1. The origin of this software must not be misrepresented; you must not
4939      claim that you wrote the original software. If you use this software in a
4940      product, an acknowledgment in the product documentation would be
4941      appreciated but is not required.
4942  
4943      2. Altered source versions must be plainly marked as such, and must not
4944      be misrepresented as being the original software.
4945  
4946      3. This notice may not be removed or altered from any source
4947      distribution.
4948  */