Compare commits
9 Commits
a81b281a0d
...
6888d4950a
Author | SHA1 | Date | |
---|---|---|---|
|
6888d4950a | ||
|
fd45553aff | ||
|
0d66f57c7e | ||
|
876f38fd20 | ||
|
61cb7c56a7 | ||
|
62077ff0d8 | ||
|
efdcdfea6e | ||
|
1fd8593da8 | ||
|
569e468cd8 |
1
.gitignore
vendored
@ -2,6 +2,5 @@ cmake-build-debug/
|
||||
cmake-build-release/
|
||||
.DS_Store
|
||||
.idea/
|
||||
build/
|
||||
node_modules/
|
||||
*.dSYM
|
||||
|
117
README.md
@ -151,6 +151,62 @@ In summary, the general order of steps is:
|
||||
|
||||
For help starting out or to discuss clay, considering joining [the discord server.](https://discord.gg/b4FTWkxdvT)
|
||||
|
||||
## Summary
|
||||
|
||||
- [High Level Documentation](#high-level-documentation)
|
||||
- [Building UI Hierarchies](#building-ui-hierarchies)
|
||||
- [Configuring Layout and Styling UI Elements](#configuring-layout-and-styling-ui-elements)
|
||||
- [Element IDs](#element-ids)
|
||||
- [Mouse, Touch and Pointer Interactions](#mouse-touch-and-pointer-interactions)
|
||||
- [Scrolling Elements](#scrolling-elements)
|
||||
- [Floating Elements](#floating-elements-absolute-positioning)
|
||||
- [Custom Elements](#laying-out-your-own-custom-elements)
|
||||
- [Retained Mode Rendering](#retained-mode-rendering)
|
||||
- [Visibility Culling](#visibility-culling)
|
||||
- [Preprocessor Directives](#preprocessor-directives)
|
||||
- [Bindings](#bindings-for-non-c)
|
||||
- [Debug Tools](#debug-tools)
|
||||
- [API](#api)
|
||||
- [Naming Conventions](#naming-conventions)
|
||||
- [Public Functions](#public-functions)
|
||||
- [Lifecycle](#lifecycle-for-public-functions)
|
||||
- [Clay_MinMemorySize](#clay_minmemorysize)
|
||||
- [Clay_CreateArenaWithCapacityAndMemory](#clay_createarenawithcapacityandmemory)
|
||||
- [Clay_SetMeasureTextFunction](#clay_setmeasuretextfunction)
|
||||
- [Clay_SetMaxElementCount](clay_setmaxelementcount)
|
||||
- [Clay_SetMaxMeasureTextCacheWordCount](#clay_setmaxmeasuretextcachewordcount)
|
||||
- [Clay_Initialize](#clay_initialize)
|
||||
- [Clay_SetLayoutDimensions](#clay_setlayoutdimensions)
|
||||
- [Clay_SetPointerState](#clay_setpointerstate)
|
||||
- [Clay_UpdateScrollContainers](#clay_updatescrollcontainers)
|
||||
- [Clay_BeginLayout](#clay_beginlayout)
|
||||
- [Clay_EndLayout](#clay_endlayout)
|
||||
- [Clay_Hovered](#clay_hovered)
|
||||
- [Clay_OnHover](#clay_onhover)
|
||||
- [Clay_PointerOver](#clay_pointerover)
|
||||
- [Clay_GetScrollContainerData](#clay_getscrollcontainerdata)
|
||||
- [Clay_GetElementId](#clay_getelementid)
|
||||
- [Element Macros](#element-macros)
|
||||
- [CLAY](#clay-1)
|
||||
- [CLAY_ID](#clay_id)
|
||||
- [CLAY_IDI](#clay_idi)
|
||||
- [CLAY_LAYOUT](#clay_layout)
|
||||
- [CLAY_RECTANGLE](#clay_rectangle)
|
||||
- [CLAY_TEXT](#clay_text)
|
||||
- [CLAY_IMAGE](#clay_image)
|
||||
- [CLAY_SCROLL](#clay_scroll)
|
||||
- [CLAY_BORDER](#clay_border)
|
||||
- [CLAY_FLOATING](#clay_floating)
|
||||
- [CLAY_CUSTOM_ELEMENT](#clay_custom_element)
|
||||
- [Data Structures & Defs](data-structures--definitions)
|
||||
- [Clay_String](#clay_string)
|
||||
- [Clay_ElementId](#clay_elementid)
|
||||
- [Clay_RenderCommandArray](#clay_rendercommandarray)
|
||||
- [Clay_RenderCommand](#clay_rendercommand)
|
||||
- [Clay_ScrollContainerData](#clay_scrollcontainerdata)
|
||||
- [Clay_ErrorHandler](#clay_errorhandler)
|
||||
- [Clay_ErrorData](#clay_errordata)
|
||||
|
||||
## High Level Documentation
|
||||
|
||||
### Building UI Hierarchies
|
||||
@ -245,7 +301,7 @@ This ID (or, if not provided, an auto generated ID) will be forwarded to the fin
|
||||
|
||||
Clay provides several functions for handling mouse and pointer interactions.
|
||||
|
||||
All pointer interactions depend on the function `void Clay_SetPointerState(Clay_Vector2 position)` being called after each mouse position update and before any other clay functions.
|
||||
All pointer interactions depend on the function `void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown)` being called after each mouse position update and before any other clay functions.
|
||||
|
||||
**During UI declaration**
|
||||
|
||||
@ -460,18 +516,24 @@ _The official Clay website with debug tooling visible_
|
||||
**Each Frame**
|
||||
`Clay_SetLayoutDimensions` -> `Clay_SetPointerState` -> `Clay_UpdateScrollContainers` -> `Clay_BeginLayout` -> `CLAY() etc...` -> `Clay_EndLayout`
|
||||
|
||||
---
|
||||
|
||||
### Clay_MinMemorySize
|
||||
|
||||
`uint32_t Clay_MinMemorySize()`
|
||||
|
||||
Returns the minimum amount of memory **in bytes** that clay needs to accomodate the current [CLAY_MAX_ELEMENT_COUNT](#preprocessor-directives).
|
||||
|
||||
---
|
||||
|
||||
### Clay_CreateArenaWithCapacityAndMemory
|
||||
|
||||
`Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset)`
|
||||
|
||||
Creates a `Clay_Arena` struct with the given capacity and base memory pointer, which can be passed to [Clay_Initialize](#clay_initialize).
|
||||
|
||||
---
|
||||
|
||||
### Clay_SetMeasureTextFunction
|
||||
|
||||
`void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config))`
|
||||
@ -482,6 +544,8 @@ Takes a pointer to a function that can be used to measure the `width, height` di
|
||||
|
||||
**Note 2: It is essential that this function is as fast as possible.** For text heavy use-cases this function is called many times, and despite the fact that clay caches text measurements internally, it can easily become the dominant overall layout cost if the provided function is slow. **This is on the hot path!**
|
||||
|
||||
---
|
||||
|
||||
### Clay_SetMaxElementCount
|
||||
|
||||
`void Clay_SetMaxElementCount(uint32_t maxElementCount)`
|
||||
@ -490,6 +554,8 @@ Updates the internal maximum element count, allowing clay to allocate larger UI
|
||||
|
||||
**Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.**
|
||||
|
||||
---
|
||||
|
||||
### Clay_SetMaxMeasureTextCacheWordCount
|
||||
|
||||
`void Clay_SetMaxMeasureTextCacheWordCount(uint32_t maxMeasureTextCacheWordCount)`
|
||||
@ -498,6 +564,8 @@ Updates the internal text measurement cache size, allowing clay to allocate more
|
||||
|
||||
**Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.**
|
||||
|
||||
---
|
||||
|
||||
### Clay_Initialize
|
||||
|
||||
`void Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler)`
|
||||
@ -506,18 +574,24 @@ Initializes the internal memory mapping, sets the internal dimensions for layout
|
||||
|
||||
Reference: [Clay_Arena](#clay_createarenawithcapacityandmemory), [Clay_ErrorHandler](#clay_errorhandler)
|
||||
|
||||
---
|
||||
|
||||
### Clay_SetLayoutDimensions
|
||||
|
||||
`void Clay_SetLayoutDimensions(Clay_Dimensions dimensions)`
|
||||
|
||||
Sets the internal layout dimensions. Cheap enough to be called every frame with your screen dimensions to automatically respond to window resizing, etc.
|
||||
|
||||
---
|
||||
|
||||
### Clay_SetPointerState
|
||||
|
||||
`void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown)`
|
||||
|
||||
Sets the internal pointer position and state (i.e. current mouse / touch position) and recalculates overlap info, which is used for mouseover / click calculation (via [Clay_PointerOver](#clay_pointerover) and updating scroll containers with [Clay_UpdateScrollContainers](#clay_updatescrollcontainers). **isPointerDown should represent the current state this frame, e.g. it should be `true` for the entire duration the left mouse button is held down.** Clay has internal handling for detecting click / touch start & end.
|
||||
|
||||
---
|
||||
|
||||
### Clay_UpdateScrollContainers
|
||||
|
||||
`void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime)`
|
||||
@ -528,24 +602,32 @@ Touch / drag scrolling only occurs if the `enableDragScrolling` parameter is `tr
|
||||
|
||||
`deltaTime` is the time **in seconds** since the last frame (e.g. 0.016 is **16 milliseconds**), and is used to normalize & smooth scrolling across different refresh rates.
|
||||
|
||||
---
|
||||
|
||||
### Clay_BeginLayout
|
||||
|
||||
`void Clay_BeginLayout()`
|
||||
|
||||
Prepares clay to calculate a new layout. Called each frame / layout **before** any of the [Element Macros](#element-macros).
|
||||
|
||||
---
|
||||
|
||||
### Clay_EndLayout
|
||||
|
||||
`Clay_RenderCommandArray Clay_EndLayout()`
|
||||
|
||||
Ends declaration of element macros and calculates the results of the current layout. Renders a [Clay_RenderCommandArray](#clay_rendercommandarray) containing the results of the layout calculation.
|
||||
|
||||
---
|
||||
|
||||
### Clay_Hovered
|
||||
|
||||
`bool Clay_Hovered()`
|
||||
|
||||
Called **during** layout declaration, and returns `true` if the pointer position previously set with `Clay_SetPointerState` is inside the bounding box of the currently open element. Note: this is based on the element's position from the **last** frame.
|
||||
|
||||
---
|
||||
|
||||
### Clay_OnHover
|
||||
|
||||
`void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData)`
|
||||
@ -570,6 +652,8 @@ CLAY(CLAY_LAYOUT({ .padding = { 8, 8 }}), Clay_OnHover(HandleButtonInteraction,
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Clay_PointerOver
|
||||
|
||||
`bool Clay_PointerOver(Clay_ElementId id)`
|
||||
@ -582,6 +666,8 @@ Returns `true` if the pointer position previously set with `Clay_SetPointerState
|
||||
|
||||
Returns [Clay_ScrollContainerData](#clay_scrollcontainerdata) for the scroll container matching the provided ID. This function allows imperative manipulation of scroll position, allowing you to build things such as scroll bars, buttons that "jump" to somewhere in a scroll container, etc.
|
||||
|
||||
---
|
||||
|
||||
### Clay_GetElementId
|
||||
|
||||
`Clay_ElementId Clay_GetElementId(Clay_String idString)`
|
||||
@ -622,6 +708,8 @@ CLAY(CLAY_ID("Outer"), CLAY_LAYOUT({ .padding = {16, 16} })) {
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CLAY_ID
|
||||
|
||||
**Usage**
|
||||
@ -656,12 +744,16 @@ if (buttonIsHovered && leftMouseButtonPressed) {
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CLAY_IDI()
|
||||
|
||||
`Clay_ElementId CLAY_IDI(char *label, int index)`
|
||||
|
||||
An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_LAYOUT
|
||||
|
||||
**Usage**
|
||||
@ -773,6 +865,8 @@ CLAY(CLAY_ID("Button"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .si
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CLAY_RECTANGLE
|
||||
**Usage**
|
||||
|
||||
@ -854,6 +948,8 @@ CLAY(
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CLAY_TEXT
|
||||
**Usage**
|
||||
|
||||
@ -975,6 +1071,8 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_
|
||||
|
||||
`Clay_RenderCommand.textContent` will be populated with a `Clay_String` _slice_ of the original string passed in (i.e. wrapping doesn't reallocate, it just returns a `Clay_String` pointing to the start of the new line with a `length`)
|
||||
|
||||
---
|
||||
|
||||
### CLAY_IMAGE
|
||||
**Usage**
|
||||
|
||||
@ -1072,6 +1170,8 @@ Image *imageToRender = renderCommand->elementConfig.imageElementConfig->imageDat
|
||||
|
||||
Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand`s with `commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE` will be created. The user will need to access `renderCommand->elementConfig.imageElementConfig->imageData` to retrieve image data referenced during layout creation. It's also up to the user to decide how / if they wish to blend `rectangleElementConfig->color` with the image.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_SCROLL
|
||||
**Usage**
|
||||
|
||||
@ -1131,6 +1231,8 @@ CLAY(CLAY_SCROLL(.vertical = true)) {
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### CLAY_BORDER
|
||||
**Usage**
|
||||
|
||||
@ -1248,6 +1350,8 @@ CLAY(
|
||||
Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand` with `commandType = CLAY_RENDER_COMMAND_TYPE_BORDER` representing the container will be created.
|
||||
Rendering of borders and rounded corners is left up to the user. See the provided [Raylib Renderer](https://github.com/nicbarker/clay/tree/main/renderers/raylib) for examples of how to draw borders using line and curve primitives.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_FLOATING
|
||||
**Usage**
|
||||
|
||||
@ -1459,6 +1563,8 @@ When using `.parentId`, the floating container can be declared anywhere after `B
|
||||
|
||||
`CLAY_FLOATING` elements will not generate any render commands.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_CUSTOM_ELEMENT
|
||||
**Usage**
|
||||
|
||||
@ -1585,6 +1691,8 @@ The number of characters in the string, _not including an optional null terminat
|
||||
|
||||
A pointer to the contents of the string. This data is not guaranteed to be null terminated, so if you are passing it to code that expects standard null terminated C strings, you will need to copy the data and append a null terminator.
|
||||
|
||||
---
|
||||
|
||||
### Clay_ElementId
|
||||
|
||||
```C
|
||||
@ -1622,6 +1730,7 @@ If this id was generated using [CLAY_IDI](#clay_idi), `.baseId` is the hash of t
|
||||
|
||||
Stores the original string that was passed in when [CLAY_ID](#clay_id) or [CLAY_IDI](#clay_idi) were called.
|
||||
|
||||
---
|
||||
|
||||
### Clay_RenderCommandArray
|
||||
|
||||
@ -1655,6 +1764,8 @@ Represents the total number of `Clay_RenderCommand` elements stored consecutivel
|
||||
|
||||
An array of [Clay_RenderCommand](#clay_rendercommand)s representing the calculated layout. If there was at least one render command, this array will contain elements from `.internalArray[0]` to `.internalArray[.length - 1]`.
|
||||
|
||||
---
|
||||
|
||||
### Clay_RenderCommand
|
||||
|
||||
```C
|
||||
@ -1721,6 +1832,8 @@ Only used if `.commandType == CLAY_RENDER_COMMAND_TYPE_TEXT`. A `Clay_String` co
|
||||
|
||||
The id that was originally used with the element macro that created this render command. See [CLAY_ID](#clay_id) for details.
|
||||
|
||||
---
|
||||
|
||||
### Clay_ScrollContainerData
|
||||
|
||||
```C
|
||||
@ -1770,6 +1883,8 @@ Dimensions representing the inner width and height of the content _inside_ the s
|
||||
|
||||
The [Clay_ScrollElementConfig](#clay_scroll) for the matching scroll container element.
|
||||
|
||||
---
|
||||
|
||||
### Clay_PointerData
|
||||
|
||||
```C
|
||||
|
176
clay.h
@ -29,43 +29,41 @@
|
||||
|
||||
// Public Macro API ------------------------
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define CLAY__CONFIG_WRAPPER(type, ...) __VA_ARGS__
|
||||
#else
|
||||
#define CLAY__CONFIG_WRAPPER(type, ...) (type) __VA_ARGS__
|
||||
#endif
|
||||
#define CLAY__WRAPPER_TYPE(type) Clay__##type##Wrapper
|
||||
#define CLAY__WRAPPER_STRUCT(type) typedef struct { type wrapped; } CLAY__WRAPPER_TYPE(type)
|
||||
#define CLAY__CONFIG_WRAPPER(type, ...) (CLAY__INIT(CLAY__WRAPPER_TYPE(type)) { __VA_ARGS__ }).wrapped
|
||||
|
||||
#define CLAY__MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
#define CLAY__MIN(x, y) (((x) < (y)) ? (x) : (y))
|
||||
|
||||
#define CLAY_LAYOUT(...) Clay__AttachLayoutConfig(Clay__StoreLayoutConfig(CLAY__CONFIG_WRAPPER(Clay_LayoutConfig, __VA_ARGS__)))
|
||||
|
||||
#define CLAY_RECTANGLE(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .rectangleElementConfig = Clay__StoreRectangleElementConfig(CLAY__INIT(Clay_RectangleElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE))
|
||||
#define CLAY_RECTANGLE(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .rectangleElementConfig = Clay__StoreRectangleElementConfig(CLAY__CONFIG_WRAPPER(Clay_RectangleElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_RECTANGLE)
|
||||
|
||||
#define CLAY_TEXT_CONFIG(...) Clay__StoreTextElementConfig(CLAY__CONFIG_WRAPPER(Clay_TextElementConfig, __VA_ARGS__))
|
||||
|
||||
#define CLAY_IMAGE(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .imageElementConfig = Clay__StoreImageElementConfig(CLAY__INIT(Clay_ImageElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE))
|
||||
#define CLAY_IMAGE(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = Clay__StoreImageElementConfig(CLAY__CONFIG_WRAPPER(Clay_ImageElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)
|
||||
|
||||
#define CLAY_FLOATING(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .floatingElementConfig = Clay__StoreFloatingElementConfig(CLAY__INIT(Clay_FloatingElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER))
|
||||
#define CLAY_FLOATING(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .floatingElementConfig = Clay__StoreFloatingElementConfig(CLAY__CONFIG_WRAPPER(Clay_FloatingElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER)
|
||||
|
||||
#define CLAY_CUSTOM_ELEMENT(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .customElementConfig = Clay__StoreCustomElementConfig(CLAY__INIT(Clay_CustomElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_CUSTOM))
|
||||
#define CLAY_CUSTOM_ELEMENT(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .customElementConfig = Clay__StoreCustomElementConfig(CLAY__CONFIG_WRAPPER(Clay_CustomElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_CUSTOM)
|
||||
|
||||
#define CLAY_SCROLL(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .scrollElementConfig = Clay__StoreScrollElementConfig(CLAY__INIT(Clay_ScrollElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER))
|
||||
#define CLAY_SCROLL(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .scrollElementConfig = Clay__StoreScrollElementConfig(CLAY__CONFIG_WRAPPER(Clay_ScrollElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER)
|
||||
|
||||
#define CLAY_BORDER(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) __VA_ARGS__) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER))
|
||||
#define CLAY_BORDER(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__CONFIG_WRAPPER(Clay_BorderElementConfig, __VA_ARGS__)) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)
|
||||
|
||||
#define CLAY_BORDER_OUTSIDE(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = __VA_ARGS__, .right = __VA_ARGS__, .top = __VA_ARGS__, .bottom = __VA_ARGS__ }) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER))
|
||||
#define CLAY_BORDER_OUTSIDE(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = __VA_ARGS__, .right = __VA_ARGS__, .top = __VA_ARGS__, .bottom = __VA_ARGS__ }) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)
|
||||
|
||||
#define CLAY_BORDER_OUTSIDE_RADIUS(width, color, radius) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = { width, color }, .right = { width, color }, .top = { width, color }, .bottom = { width, color }, .cornerRadius = { radius, radius, radius, radius } })}, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER))
|
||||
#define CLAY_BORDER_OUTSIDE_RADIUS(width, color, radius) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = { width, color }, .right = { width, color }, .top = { width, color }, .bottom = { width, color }, .cornerRadius = CLAY_CORNER_RADIUS(radius) })}, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)
|
||||
|
||||
#define CLAY_BORDER_ALL(...) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = __VA_ARGS__, .right = __VA_ARGS__, .top = __VA_ARGS__, .bottom = __VA_ARGS__, .betweenChildren = __VA_ARGS__ }) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER))
|
||||
#define CLAY_BORDER_ALL(...) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = __VA_ARGS__, .right = __VA_ARGS__, .top = __VA_ARGS__, .bottom = __VA_ARGS__, .betweenChildren = __VA_ARGS__ }) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)
|
||||
|
||||
#define CLAY_BORDER_ALL_RADIUS(width, color, radius) Clay__AttachElementConfig(CLAY__CONFIG_WRAPPER(Clay_ElementConfigUnion, { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = { width, color }, .right = { width, color }, .top = { width, color }, .bottom = { width, color }, .betweenChildren = { width, color }, .cornerRadius = { radius, radius, radius, radius }}) }))
|
||||
#define CLAY_BORDER_ALL_RADIUS(width, color, radius) Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .borderElementConfig = Clay__StoreBorderElementConfig(CLAY__INIT(Clay_BorderElementConfig) { .left = { width, color }, .right = { width, color }, .top = { width, color }, .bottom = { width, color }, .betweenChildren = { width, color }, .cornerRadius = CLAY_CORNER_RADIUS(radius)}) }, CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER)
|
||||
|
||||
#define CLAY_CORNER_RADIUS(radius) (CLAY__INIT(Clay_CornerRadius) { radius, radius, radius, radius })
|
||||
|
||||
#define CLAY__STRUCT_1_ARGS(a) a
|
||||
#define CLAY__STRUCT_0_ARGS() {0}
|
||||
#define CLAY__STRUCT_0_ARGS() CLAY__DEFAULT_STRUCT
|
||||
#define CLAY__STRUCT_OVERRIDE(_0, _1, NAME, ...) NAME
|
||||
|
||||
#define CLAY__SIZING_FIT_INTERNAL(...) (CLAY__INIT(Clay_SizingAxis) { .size = { .minMax = __VA_ARGS__ }, .type = CLAY__SIZING_TYPE_FIT })
|
||||
@ -127,17 +125,22 @@ static uint8_t CLAY__ELEMENT_DEFINITION_LATCH;
|
||||
#define CLAY_TEXT(text, textConfig) Clay__OpenTextElement(text, textConfig)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#define CLAY__INIT(type) type
|
||||
#define CLAY__TYPEDEF(name, ...) typedef __VA_ARGS__ name
|
||||
#define CLAY__TYPEDEF(name, ...) typedef __VA_ARGS__ name; CLAY__WRAPPER_STRUCT(name)
|
||||
#define CLAY__ALIGNMENT(type) alignof(type)
|
||||
#define CLAY__POINTER_ALIGNMENT alignof(void *)
|
||||
|
||||
#define CLAY_PACKED_ENUM enum : uint8_t
|
||||
|
||||
#define CLAY__DEFAULT_STRUCT {}
|
||||
|
||||
#else
|
||||
|
||||
#define CLAY__INIT(type) (type)
|
||||
|
||||
#define CLAY__ALIGNMENT_STRUCT(type) struct Clay__Align##type { char c; type x; }
|
||||
#define CLAY__TYPEDEF(name, ...) typedef __VA_ARGS__ name; CLAY__ALIGNMENT_STRUCT(name)
|
||||
#define CLAY__TYPEDEF(name, ...) typedef __VA_ARGS__ name; CLAY__ALIGNMENT_STRUCT(name); CLAY__WRAPPER_STRUCT(name)
|
||||
#define CLAY__ALIGNMENT(type) (offsetof(struct Clay__Align##type, x))
|
||||
#define CLAY__POINTER_ALIGNMENT CLAY__ALIGNMENT(pointer)
|
||||
|
||||
@ -152,8 +155,15 @@ CLAY__ALIGNMENT_STRUCT(int32_t);
|
||||
#else
|
||||
#define CLAY_PACKED_ENUM enum __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#if __STDC_VERSION__ >= 202311L
|
||||
#define CLAY__DEFAULT_STRUCT {}
|
||||
#else
|
||||
#define CLAY__DEFAULT_STRUCT {0}
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -565,7 +575,7 @@ CLAY__TYPEDEF(Clay__Warning, struct {
|
||||
Clay_String dynamicMessage;
|
||||
});
|
||||
|
||||
Clay__Warning CLAY__WARNING_DEFAULT = {0};
|
||||
Clay__Warning CLAY__WARNING_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
#pragma region generated
|
||||
CLAY__TYPEDEF(Clay__WarningArray, struct {
|
||||
@ -593,7 +603,7 @@ Clay__WarningArray Clay__WarningArray_Allocate_Arena(int32_t capacity, Clay_Aren
|
||||
return array;
|
||||
}
|
||||
|
||||
Clay__WarningArray Clay_warnings = {0};
|
||||
Clay__WarningArray Clay_warnings = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning item)
|
||||
{
|
||||
@ -663,7 +673,7 @@ Clay__BoolArray Clay__BoolArray_Allocate_Arena(int32_t capacity, Clay_Arena *are
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_ElementId CLAY__ELEMENT_ID_DEFAULT = {0};
|
||||
Clay_ElementId CLAY__ELEMENT_ID_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_get,array_add TYPE=Clay_ElementId NAME=Clay__ElementIdArray DEFAULT_VALUE=&CLAY__ELEMENT_ID_DEFAULT
|
||||
#pragma region generated
|
||||
@ -689,7 +699,7 @@ Clay_ElementId *Clay__ElementIdArray_Add(Clay__ElementIdArray *array, Clay_Eleme
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_ElementConfig CLAY__ELEMENT_CONFIG_DEFAULT = {CLAY__ELEMENT_CONFIG_TYPE_NONE, {0}};
|
||||
Clay_ElementConfig CLAY__ELEMENT_CONFIG_DEFAULT = {CLAY__ELEMENT_CONFIG_TYPE_NONE, CLAY__DEFAULT_STRUCT};
|
||||
|
||||
// __GENERATED__ template array_define,array_define_slice,array_allocate,array_get,array_add,array_get_slice TYPE=Clay_ElementConfig NAME=Clay__ElementConfigArray DEFAULT_VALUE=&CLAY__ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -746,7 +756,7 @@ Clay_LayoutConfig *Clay__LayoutConfigArray_Add(Clay__LayoutConfigArray *array, C
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_RectangleElementConfig CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_RectangleElementConfig CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_RectangleElementConfig NAME=Clay__RectangleElementConfigArray DEFAULT_VALUE=&CLAY__RECTANGLE_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -769,7 +779,7 @@ Clay_RectangleElementConfig *Clay__RectangleElementConfigArray_Add(Clay__Rectang
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_TextElementConfig CLAY__TEXT_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_TextElementConfig CLAY__TEXT_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_TextElementConfig NAME=Clay__TextElementConfigArray DEFAULT_VALUE=&CLAY__TEXT_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -792,7 +802,7 @@ Clay_TextElementConfig *Clay__TextElementConfigArray_Add(Clay__TextElementConfig
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_ImageElementConfig CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_ImageElementConfig CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_ImageElementConfig NAME=Clay__ImageElementConfigArray DEFAULT_VALUE=&CLAY__IMAGE_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -815,7 +825,7 @@ Clay_ImageElementConfig *Clay__ImageElementConfigArray_Add(Clay__ImageElementCon
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_FloatingElementConfig CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_FloatingElementConfig CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_FloatingElementConfig NAME=Clay__FloatingElementConfigArray DEFAULT_VALUE=&CLAY__FLOATING_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -838,7 +848,7 @@ Clay_FloatingElementConfig *Clay__FloatingElementConfigArray_Add(Clay__FloatingE
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_CustomElementConfig CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_CustomElementConfig CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_CustomElementConfig NAME=Clay__CustomElementConfigArray DEFAULT_VALUE=&CLAY__CUSTOM_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -861,7 +871,7 @@ Clay_CustomElementConfig *Clay__CustomElementConfigArray_Add(Clay__CustomElement
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_ScrollElementConfig CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_ScrollElementConfig CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_ScrollElementConfig NAME=Clay__ScrollElementConfigArray DEFAULT_VALUE=&CLAY__SCROLL_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -909,7 +919,7 @@ CLAY__TYPEDEF(Clay__WrappedTextLine, struct {
|
||||
Clay_String line;
|
||||
});
|
||||
|
||||
Clay__WrappedTextLine CLAY__WRAPPED_TEXT_LINE_DEFAULT = {0};
|
||||
Clay__WrappedTextLine CLAY__WRAPPED_TEXT_LINE_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_define_slice,array_allocate,array_add,array_get TYPE=Clay__WrappedTextLine NAME=Clay__WrappedTextLineArray DEFAULT_VALUE=&CLAY__WRAPPED_TEXT_LINE_DEFAULT
|
||||
#pragma region generated
|
||||
@ -947,7 +957,7 @@ CLAY__TYPEDEF(Clay__TextElementData, struct {
|
||||
Clay__WrappedTextLineArraySlice wrappedLines;
|
||||
});
|
||||
|
||||
Clay__TextElementData CLAY__TEXT_ELEMENT_DATA_DEFAULT = {0};
|
||||
Clay__TextElementData CLAY__TEXT_ELEMENT_DATA_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_get,array_add TYPE=Clay__TextElementData NAME=Clay__TextElementDataArray DEFAULT_VALUE=&CLAY__TEXT_ELEMENT_DATA_DEFAULT
|
||||
#pragma region generated
|
||||
@ -973,7 +983,7 @@ Clay__TextElementData *Clay__TextElementDataArray_Add(Clay__TextElementDataArray
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_BorderElementConfig CLAY__BORDER_ELEMENT_CONFIG_DEFAULT = {0};
|
||||
Clay_BorderElementConfig CLAY__BORDER_ELEMENT_CONFIG_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add TYPE=Clay_BorderElementConfig NAME=Clay__BorderElementConfigArray DEFAULT_VALUE=&CLAY__BORDER_ELEMENT_CONFIG_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1014,7 +1024,7 @@ CLAY__TYPEDEF(Clay_LayoutElement, struct {
|
||||
uint32_t id;
|
||||
});
|
||||
|
||||
Clay_LayoutElement CLAY__LAYOUT_ELEMENT_DEFAULT = {0};
|
||||
Clay_LayoutElement CLAY__LAYOUT_ELEMENT_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add,array_get TYPE=Clay_LayoutElement NAME=Clay_LayoutElementArray DEFAULT_VALUE=&CLAY__LAYOUT_ELEMENT_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1073,7 +1083,7 @@ Clay_LayoutElement* Clay__LayoutElementPointerArray_RemoveSwapback(Clay__LayoutE
|
||||
#pragma endregion
|
||||
// __GENERATED__ template
|
||||
|
||||
Clay_RenderCommand CLAY__RENDER_COMMAND_DEFAULT = {0};
|
||||
Clay_RenderCommand CLAY__RENDER_COMMAND_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_allocate,array_add,array_get TYPE=Clay_RenderCommand NAME=Clay_RenderCommandArray DEFAULT_VALUE=&CLAY__RENDER_COMMAND_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1108,7 +1118,7 @@ CLAY__TYPEDEF(Clay__ScrollContainerDataInternal, struct {
|
||||
bool pointerScrollActive;
|
||||
});
|
||||
|
||||
Clay__ScrollContainerDataInternal CLAY__SCROLL_CONTAINER_DEFAULT = {0};
|
||||
Clay__ScrollContainerDataInternal CLAY__SCROLL_CONTAINER_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add,array_get TYPE=Clay__ScrollContainerDataInternal NAME=Clay__ScrollContainerDataInternalArray DEFAULT_VALUE=&CLAY__SCROLL_CONTAINER_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1153,7 +1163,7 @@ CLAY__TYPEDEF(Clay__DebugElementData, struct {
|
||||
bool collapsed;
|
||||
});
|
||||
|
||||
Clay__DebugElementData CLAY__DEBUG_ELEMENT_DATA_DEFAULT = {0};
|
||||
Clay__DebugElementData CLAY__DEBUG_ELEMENT_DATA_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add,array_get TYPE=Clay__DebugElementData NAME=Clay__DebugElementDataArray DEFAULT_VALUE=&CLAY__DEBUG_ELEMENT_DATA_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1339,7 +1349,7 @@ CLAY__TYPEDEF(Clay__LayoutElementTreeNode, struct {
|
||||
Clay_Vector2 nextChildOffset;
|
||||
});
|
||||
|
||||
Clay__LayoutElementTreeNode CLAY__LAYOUT_ELEMENT_TREE_NODE_DEFAULT = {0};
|
||||
Clay__LayoutElementTreeNode CLAY__LAYOUT_ELEMENT_TREE_NODE_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add,array_get TYPE=Clay__LayoutElementTreeNode NAME=Clay__LayoutElementTreeNodeArray DEFAULT_VALUE=&CLAY__LAYOUT_ELEMENT_TREE_NODE_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1373,7 +1383,7 @@ CLAY__TYPEDEF(Clay__LayoutElementTreeRoot, struct {
|
||||
Clay_Vector2 pointerOffset; // Only used when scroll containers are managed externally
|
||||
});
|
||||
|
||||
Clay__LayoutElementTreeRoot CLAY__LAYOUT_ELEMENT_TREE_ROOT_DEFAULT = {0};
|
||||
Clay__LayoutElementTreeRoot CLAY__LAYOUT_ELEMENT_TREE_ROOT_DEFAULT = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// __GENERATED__ template array_define,array_allocate,array_add,array_get TYPE=Clay__LayoutElementTreeRoot NAME=Clay__LayoutElementTreeRootArray DEFAULT_VALUE=&CLAY__LAYOUT_ELEMENT_TREE_ROOT_DEFAULT
|
||||
#pragma region generated
|
||||
@ -1423,7 +1433,7 @@ Clay_String Clay__WriteStringToCharBuffer(Clay__CharArray *buffer, Clay_String s
|
||||
|
||||
// Global Variable Definitions ----------------------------------------------
|
||||
Clay_PointerData Clay__pointerInfo = { .position = {-1, -1} };
|
||||
Clay_Dimensions Clay__layoutDimensions = {0};
|
||||
Clay_Dimensions Clay__layoutDimensions = CLAY__DEFAULT_STRUCT;
|
||||
Clay_ElementId Clay__dynamicElementIndexBaseHash = { .id = 128476991, .stringId = { .length = 8, .chars = "Auto ID" } };
|
||||
uint32_t Clay__dynamicElementIndex = 0;
|
||||
bool Clay__debugModeEnabled = false;
|
||||
@ -1776,7 +1786,7 @@ Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Cl
|
||||
hashItemIndex = hashItem->nextIndex;
|
||||
}
|
||||
Clay_LayoutElementHashMapItem *hashItem = Clay__LayoutElementHashMapItemArray_Add(&Clay__layoutElementsHashMapInternal, item);
|
||||
hashItem->debugData = Clay__DebugElementDataArray_Add(&Clay__debugElementData, CLAY__INIT(Clay__DebugElementData) {0});
|
||||
hashItem->debugData = Clay__DebugElementDataArray_Add(&Clay__debugElementData, CLAY__INIT(Clay__DebugElementData) CLAY__DEFAULT_STRUCT);
|
||||
if (hashItemPrevious != -1) {
|
||||
Clay__LayoutElementHashMapItemArray_Get(&Clay__layoutElementsHashMapInternal, hashItemPrevious)->nextIndex = (int32_t)Clay__layoutElementsHashMapInternal.length - 1;
|
||||
} else {
|
||||
@ -1995,7 +2005,7 @@ void Clay__OpenElement(void) {
|
||||
Clay__booleanWarnings.maxElementsExceeded = true;
|
||||
return;
|
||||
}
|
||||
Clay_LayoutElement layoutElement = {0};
|
||||
Clay_LayoutElement layoutElement = CLAY__DEFAULT_STRUCT;
|
||||
Clay_LayoutElementArray_Add(&Clay__layoutElements, layoutElement);
|
||||
Clay__int32_tArray_Add(&Clay__openLayoutElementStack, Clay__layoutElements.length - 1);
|
||||
if (Clay__openClipElementStack.length > 0) {
|
||||
@ -2491,7 +2501,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
dfsBuffer.length = 0;
|
||||
Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&Clay__layoutElementTreeRoots, rootIndex);
|
||||
Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&Clay__layoutElements, (int)root->layoutElementIndex);
|
||||
Clay_Vector2 rootPosition = {0};
|
||||
Clay_Vector2 rootPosition = CLAY__DEFAULT_STRUCT;
|
||||
Clay_LayoutElementHashMapItem *parentHashMapItem = Clay__GetHashMapItem(root->parentId);
|
||||
// Position root floating containers
|
||||
if (Clay__ElementHasConfig(rootElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER) && parentHashMapItem) {
|
||||
@ -2499,7 +2509,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
Clay_Dimensions rootDimensions = rootElement->dimensions;
|
||||
Clay_BoundingBox parentBoundingBox = parentHashMapItem->boundingBox;
|
||||
// Set X position
|
||||
Clay_Vector2 targetAttachPosition = {0};
|
||||
Clay_Vector2 targetAttachPosition = CLAY__DEFAULT_STRUCT;
|
||||
switch (config->attachment.parent) {
|
||||
case CLAY_ATTACH_POINT_LEFT_TOP:
|
||||
case CLAY_ATTACH_POINT_LEFT_CENTER:
|
||||
@ -2570,7 +2580,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
}
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = clipHashMapItem->boundingBox,
|
||||
.config = { .scrollElementConfig = Clay__StoreScrollElementConfig(CLAY__INIT(Clay_ScrollElementConfig){0}) },
|
||||
.config = { .scrollElementConfig = Clay__StoreScrollElementConfig(CLAY__INIT(Clay_ScrollElementConfig)CLAY__DEFAULT_STRUCT) },
|
||||
.id = Clay__RehashWithNumber(rootElement->id, 10), // TODO need a better strategy for managing derived ids
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
|
||||
});
|
||||
@ -2583,7 +2593,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1);
|
||||
Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement;
|
||||
Clay_LayoutConfig *layoutConfig = currentElement->layoutConfig;
|
||||
Clay_Vector2 scrollOffset = {0};
|
||||
Clay_Vector2 scrollOffset = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// This will only be run a single time for each element in downwards DFS order
|
||||
if (!Clay__treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
|
||||
@ -2617,7 +2627,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
scrollOffset.y = mapping->scrollPosition.y;
|
||||
}
|
||||
if (Clay__externalScrollHandlingEnabled) {
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) {0};
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2781,7 +2791,7 @@ void Clay__CalculateFinalLayout(void) {
|
||||
if (scrollConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; }
|
||||
if (scrollConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; }
|
||||
if (Clay__externalScrollHandlingEnabled) {
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) {0};
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -2944,7 +2954,7 @@ const int32_t CLAY__DEBUGVIEW_ROW_HEIGHT = 30;
|
||||
const int32_t CLAY__DEBUGVIEW_OUTER_PADDING = 10;
|
||||
const int32_t CLAY__DEBUGVIEW_INDENT_WIDTH = 16;
|
||||
Clay_TextElementConfig Clay__DebugView_TextNameConfig = {.textColor = {238, 226, 231, 255}, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE };
|
||||
Clay_LayoutConfig Clay__DebugView_ScrollViewItemLayoutConfig = {0};
|
||||
Clay_LayoutConfig Clay__DebugView_ScrollViewItemLayoutConfig = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
CLAY__TYPEDEF(Clay__DebugElementConfigTypeLabelConfig, struct {
|
||||
Clay_String label;
|
||||
@ -2974,7 +2984,7 @@ CLAY__TYPEDEF(Clay__RenderDebugLayoutData, struct {
|
||||
Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialRootsLength, int32_t highlightedRowIndex) {
|
||||
Clay__int32_tArray dfsBuffer = Clay__reusableElementIndexBuffer;
|
||||
Clay__DebugView_ScrollViewItemLayoutConfig = CLAY__INIT(Clay_LayoutConfig) { .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT) }, .childGap = 6, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }};
|
||||
Clay__RenderDebugLayoutData layoutData = {0};
|
||||
Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
uint32_t highlightedElementId = 0;
|
||||
|
||||
@ -2984,8 +2994,8 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
|
||||
Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex);
|
||||
Clay__treeNodeVisited.internalArray[0] = false;
|
||||
if (rootIndex > 0) {
|
||||
CLAY(CLAY_IDI("Clay__DebugView_EmptyRowOuter", rootIndex), CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW({0})}, .padding = {CLAY__DEBUGVIEW_INDENT_WIDTH / 2, 0} })) {
|
||||
CLAY(CLAY_IDI("Clay__DebugView_EmptyRow", rootIndex), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW({0}), .height = CLAY_SIZING_FIXED((float)CLAY__DEBUGVIEW_ROW_HEIGHT) }}), CLAY_BORDER({ .top = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 } })) {}
|
||||
CLAY(CLAY_IDI("Clay__DebugView_EmptyRowOuter", rootIndex), CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .padding = {CLAY__DEBUGVIEW_INDENT_WIDTH / 2, 0} })) {
|
||||
CLAY(CLAY_IDI("Clay__DebugView_EmptyRow", rootIndex), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .height = CLAY_SIZING_FIXED((float)CLAY__DEBUGVIEW_ROW_HEIGHT) }}), CLAY_BORDER({ .top = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 } })) {}
|
||||
}
|
||||
layoutData.rowCount++;
|
||||
}
|
||||
@ -3062,8 +3072,8 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
|
||||
layoutData.rowCount++;
|
||||
Clay__TextElementData *textElementData = currentElement->childrenOrTextContent.textElementData;
|
||||
Clay_TextElementConfig *rawTextConfig = offscreen ? CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16 }) : &Clay__DebugView_TextNameConfig;
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_RECTANGLE({0})) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_INDENT_WIDTH + 16), {0}} })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { .height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_RECTANGLE(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_INDENT_WIDTH + 16), CLAY__DEFAULT_STRUCT} })) {}
|
||||
CLAY_TEXT(CLAY_STRING("\""), rawTextConfig);
|
||||
CLAY_TEXT(textElementData->text.length > 40 ? (CLAY__INIT(Clay_String) { .length = 40, .chars = textElementData->text.chars }) : textElementData->text, rawTextConfig);
|
||||
if (textElementData->text.length > 40) {
|
||||
@ -3078,7 +3088,7 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
|
||||
Clay__OpenElement();
|
||||
CLAY_BORDER({ .left = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 }});
|
||||
Clay__ElementPostConfiguration();
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED( CLAY__DEBUGVIEW_INDENT_WIDTH), {0}}, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED( CLAY__DEBUGVIEW_INDENT_WIDTH), CLAY__DEFAULT_STRUCT}, .childAlignment = { .x = CLAY_ALIGN_X_RIGHT } })) {}
|
||||
Clay__OpenElement();
|
||||
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM });
|
||||
Clay__ElementPostConfiguration();
|
||||
@ -3107,8 +3117,8 @@ Clay__RenderDebugLayoutData Clay__RenderDebugLayoutElementsList(int32_t initialR
|
||||
}
|
||||
|
||||
if (highlightedElementId) {
|
||||
CLAY(CLAY_ID("Clay__DebugView_ElementHighlight"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})} }), CLAY_FLOATING({ .zIndex = 65535, .parentId = highlightedElementId })) {
|
||||
CLAY(CLAY_ID("Clay__DebugView_ElementHighlightRectangle"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})} }), CLAY_RECTANGLE({.color = Clay__debugViewHighlightColor })) {}
|
||||
CLAY(CLAY_ID("Clay__DebugView_ElementHighlight"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_FLOATING({ .zIndex = 65535, .parentId = highlightedElementId })) {
|
||||
CLAY(CLAY_ID("Clay__DebugView_ElementHighlightRectangle"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_RECTANGLE({.color = Clay__debugViewHighlightColor })) {}
|
||||
}
|
||||
}
|
||||
return layoutData;
|
||||
@ -3143,11 +3153,11 @@ void Clay__RenderDebugViewElementConfigHeader(Clay_String elementId, Clay__Eleme
|
||||
Clay__DebugElementConfigTypeLabelConfig config = Clay__DebugGetElementConfigTypeLabel(type);
|
||||
Clay_Color backgroundColor = config.color;
|
||||
backgroundColor.a = 90;
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = { .x = CLAY__DEBUGVIEW_OUTER_PADDING }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = { .x = CLAY__DEBUGVIEW_OUTER_PADDING }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } })) {
|
||||
CLAY(CLAY_LAYOUT({ .padding = { 8, 2 } }), CLAY_RECTANGLE({ .color = backgroundColor, .cornerRadius = CLAY_CORNER_RADIUS(4) }), CLAY_BORDER_OUTSIDE_RADIUS(1, config.color, 4)) {
|
||||
CLAY_TEXT(config.label, CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
|
||||
}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW({0}) } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT) } })) {}
|
||||
CLAY_TEXT(elementId, CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_3, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }));
|
||||
}
|
||||
}
|
||||
@ -3163,7 +3173,7 @@ void Clay__RenderDebugViewColor(Clay_Color color, Clay_TextElementConfig *textCo
|
||||
CLAY_TEXT(CLAY_STRING(", a: "), textConfig);
|
||||
CLAY_TEXT(Clay__IntToString(color.a), textConfig);
|
||||
CLAY_TEXT(CLAY_STRING(" }"), textConfig);
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(10), {0} } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(10), CLAY__DEFAULT_STRUCT } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8)} }), CLAY_BORDER_OUTSIDE_RADIUS(1, CLAY__DEBUGVIEW_COLOR_4, 4)) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 8)} }), CLAY_RECTANGLE({ .color = color, .cornerRadius = CLAY_CORNER_RADIUS(4) })) {}
|
||||
}
|
||||
@ -3235,15 +3245,15 @@ void Clay__RenderDebugView(void) {
|
||||
if (Clay__pointerInfo.position.x < Clay__layoutDimensions.width - (float)Clay__debugViewWidth) {
|
||||
highlightedRow = -1;
|
||||
}
|
||||
Clay__RenderDebugLayoutData layoutData = {0};
|
||||
Clay__RenderDebugLayoutData layoutData = CLAY__DEFAULT_STRUCT;
|
||||
CLAY(CLAY_ID("Clay__DebugView"),
|
||||
CLAY_FLOATING({ .parentId = Clay__HashString(CLAY_STRING("Clay__RootContainer"), 0, 0).id, .attachment = { .element = CLAY_ATTACH_POINT_LEFT_CENTER, .parent = CLAY_ATTACH_POINT_RIGHT_CENTER }}),
|
||||
CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED((float)Clay__debugViewWidth) , CLAY_SIZING_FIXED(Clay__layoutDimensions.height) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }),
|
||||
CLAY_BORDER({ .bottom = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 }})
|
||||
) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) {
|
||||
CLAY_TEXT(CLAY_STRING("Clay Debug Tools"), infoTextConfig);
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({0}), {0} } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY__DEFAULT_STRUCT } })) {}
|
||||
// Close button
|
||||
CLAY(CLAY_BORDER_OUTSIDE_RADIUS(1, (CLAY__INIT(Clay_Color){217,91,67,255}), 4),
|
||||
CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 10), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT - 10)}, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER} }),
|
||||
@ -3253,18 +3263,18 @@ void Clay__RenderDebugView(void) {
|
||||
CLAY_TEXT(CLAY_STRING("x"), CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16 }));
|
||||
}
|
||||
}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {}
|
||||
CLAY(Clay__AttachId(scrollId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})} }), CLAY_SCROLL({ .horizontal = true, .vertical = true })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {}
|
||||
CLAY(Clay__AttachId(scrollId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_SCROLL({ .horizontal = true, .vertical = true })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 })) {
|
||||
Clay_ElementId panelContentsId = Clay__HashString(CLAY_STRING("Clay__DebugViewPaneOuter"), 0, 0);
|
||||
// Element list
|
||||
CLAY(Clay__AttachId(panelContentsId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})} }), CLAY_FLOATING({ .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_GROW({0})}, .padding = {.x = CLAY__DEBUGVIEW_OUTER_PADDING }, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
|
||||
CLAY(Clay__AttachId(panelContentsId), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)} }), CLAY_FLOATING({ .pointerCaptureMode = CLAY_POINTER_CAPTURE_MODE_PASSTHROUGH })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT)}, .padding = {.x = CLAY__DEBUGVIEW_OUTER_PADDING }, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
|
||||
layoutData = Clay__RenderDebugLayoutElementsList((int32_t)initialRootsLength, highlightedRow);
|
||||
}
|
||||
}
|
||||
float contentWidth = Clay__GetHashMapItem(panelContentsId.id)->layoutElement->dimensions.width;
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(contentWidth), {0}}, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(contentWidth), CLAY__DEFAULT_STRUCT}, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {}
|
||||
for (int32_t i = 0; i < layoutData.rowCount; i++) {
|
||||
Clay_Color rowColor = (i & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1;
|
||||
if (i == layoutData.selectedElementRowIndex) {
|
||||
@ -3275,22 +3285,22 @@ void Clay__RenderDebugView(void) {
|
||||
rowColor.g *= 1.25f;
|
||||
rowColor.b *= 1.25f;
|
||||
}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = rowColor })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_RECTANGLE({ .color = rowColor })) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW({0}), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {.width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_3 })) {}
|
||||
if (Clay__debugSelectedElementId != 0) {
|
||||
Clay_LayoutElementHashMapItem *selectedItem = Clay__GetHashMapItem(Clay__debugSelectedElementId);
|
||||
CLAY(
|
||||
CLAY_SCROLL({ .vertical = true }),
|
||||
CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }),
|
||||
CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }),
|
||||
CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 }),
|
||||
CLAY_BORDER({ .betweenChildren = { .width = 1, .color = CLAY__DEBUGVIEW_COLOR_3 }})
|
||||
) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) {
|
||||
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) {
|
||||
CLAY_TEXT(CLAY_STRING("Layout Config"), infoTextConfig);
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({0}), {0} } })) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY__DEFAULT_STRUCT } })) {}
|
||||
if (selectedItem->elementId.stringId.length != 0) {
|
||||
CLAY_TEXT(selectedItem->elementId.stringId, infoTitleConfig);
|
||||
if (selectedItem->elementId.offset != 0) {
|
||||
@ -3304,7 +3314,7 @@ void Clay__RenderDebugView(void) {
|
||||
CLAY(CLAY_LAYOUT({ .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
|
||||
// .boundingBox
|
||||
CLAY_TEXT(CLAY_STRING("Bounding Box"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
|
||||
CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.x), infoTextConfig);
|
||||
CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig);
|
||||
@ -3321,11 +3331,11 @@ void Clay__RenderDebugView(void) {
|
||||
CLAY_TEXT(layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM ? CLAY_STRING("TOP_TO_BOTTOM") : CLAY_STRING("LEFT_TO_RIGHT"), infoTextConfig);
|
||||
// .sizing
|
||||
CLAY_TEXT(CLAY_STRING("Sizing"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("width: "), infoTextConfig);
|
||||
Clay__RenderDebugLayoutSizing(layoutConfig->sizing.width, infoTextConfig);
|
||||
}
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("height: "), infoTextConfig);
|
||||
Clay__RenderDebugLayoutSizing(layoutConfig->sizing.height, infoTextConfig);
|
||||
}
|
||||
@ -3343,7 +3353,7 @@ void Clay__RenderDebugView(void) {
|
||||
CLAY_TEXT(Clay__IntToString(layoutConfig->childGap), infoTextConfig);
|
||||
// .childAlignment
|
||||
CLAY_TEXT(CLAY_STRING("Child Alignment"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
|
||||
Clay_String alignX = CLAY_STRING("LEFT");
|
||||
if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_CENTER) {
|
||||
@ -3423,7 +3433,7 @@ void Clay__RenderDebugView(void) {
|
||||
}
|
||||
// Image Preview
|
||||
CLAY_TEXT(CLAY_STRING("Preview"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = imageConfig->sourceDimensions.width }), {0} }}), Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = imageConfig }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) {}
|
||||
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = imageConfig->sourceDimensions.width }), CLAY__DEFAULT_STRUCT }}), Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = imageConfig }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) {}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -3444,7 +3454,7 @@ void Clay__RenderDebugView(void) {
|
||||
CLAY(CLAY_LAYOUT({ .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 8}, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
|
||||
// .offset
|
||||
CLAY_TEXT(CLAY_STRING("Offset"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig);
|
||||
CLAY_TEXT(Clay__IntToString(floatingConfig->offset.x), infoTextConfig);
|
||||
CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig);
|
||||
@ -3453,7 +3463,7 @@ void Clay__RenderDebugView(void) {
|
||||
}
|
||||
// .expand
|
||||
CLAY_TEXT(CLAY_STRING("Expand"), infoTitleConfig);
|
||||
CLAY(CLAY_LAYOUT({0})) {
|
||||
CLAY(CLAY_LAYOUT(CLAY__DEFAULT_STRUCT)) {
|
||||
CLAY_TEXT(CLAY_STRING("{ width: "), infoTextConfig);
|
||||
CLAY_TEXT(Clay__IntToString(floatingConfig->expand.width), infoTextConfig);
|
||||
CLAY_TEXT(CLAY_STRING(", height: "), infoTextConfig);
|
||||
@ -3500,12 +3510,12 @@ void Clay__RenderDebugView(void) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CLAY(CLAY_ID("Clay__DebugViewWarningsScrollPane"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW({0}), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_SCROLL({ .horizontal = true, .vertical = true }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) {
|
||||
CLAY(CLAY_ID("Clay__DebugViewWarningsScrollPane"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_SCROLL({ .horizontal = true, .vertical = true }), CLAY_RECTANGLE({ .color = CLAY__DEBUGVIEW_COLOR_2 })) {
|
||||
Clay_TextElementConfig *warningConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE });
|
||||
CLAY(CLAY_ID("Clay__DebugViewWarningItemHeader"), CLAY_LAYOUT({ .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, 0}, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} })) {
|
||||
CLAY_TEXT(CLAY_STRING("Warnings"), warningConfig);
|
||||
}
|
||||
CLAY(CLAY_ID("Clay__DebugViewWarningsTopBorder"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW({0}), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = {200, 200, 200, 255} })) {}
|
||||
CLAY(CLAY_ID("Clay__DebugViewWarningsTopBorder"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(CLAY__DEFAULT_STRUCT), .height = CLAY_SIZING_FIXED(1)} }), CLAY_RECTANGLE({ .color = {200, 200, 200, 255} })) {}
|
||||
int32_t previousWarningsLength = (int)Clay_warnings.length;
|
||||
for (int32_t i = 0; i < previousWarningsLength; i++) {
|
||||
Clay__Warning warning = Clay_warnings.internalArray[i];
|
||||
@ -3716,7 +3726,7 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe
|
||||
}
|
||||
// Handle click / touch scroll
|
||||
if (isPointerActive) {
|
||||
highestPriorityScrollData->scrollMomentum = CLAY__INIT(Clay_Vector2){0};
|
||||
highestPriorityScrollData->scrollMomentum = CLAY__INIT(Clay_Vector2)CLAY__DEFAULT_STRUCT;
|
||||
if (!highestPriorityScrollData->pointerScrollActive) {
|
||||
highestPriorityScrollData->pointerOrigin = Clay__pointerInfo.position;
|
||||
highestPriorityScrollData->scrollOrigin = highestPriorityScrollData->scrollPosition;
|
||||
@ -3857,7 +3867,7 @@ Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id) {
|
||||
};
|
||||
}
|
||||
}
|
||||
return CLAY__INIT(Clay_ScrollContainerData) {0};
|
||||
return CLAY__INIT(Clay_ScrollContainerData) CLAY__DEFAULT_STRUCT;
|
||||
}
|
||||
|
||||
CLAY_WASM_EXPORT("Clay_SetDebugModeEnabled")
|
||||
|
BIN
examples/clay-official-website/build/clay/images/check_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/clay-official-website/build/clay/images/check_2.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/clay-official-website/build/clay/images/check_3.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/clay-official-website/build/clay/images/check_4.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/clay-official-website/build/clay/images/check_5.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
examples/clay-official-website/build/clay/images/debugger.png
Normal file
After Width: | Height: | Size: 296 KiB |
BIN
examples/clay-official-website/build/clay/images/declarative.png
Normal file
After Width: | Height: | Size: 193 KiB |
BIN
examples/clay-official-website/build/clay/images/renderer.png
Normal file
After Width: | Height: | Size: 310 KiB |
789
examples/clay-official-website/build/clay/index.html
Normal file
@ -0,0 +1,789 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="preload" href="/clay/fonts/Calistoga-Regular.ttf" as="font" type="font/ttf" crossorigin>
|
||||
<link rel="preload" href="/clay/fonts/Quicksand-Semibold.ttf" as="font" type="font/ttf" crossorigin>
|
||||
<title>Clay - UI Layout Library</title>
|
||||
<style>
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
pointer-events: none;
|
||||
background: rgb(244, 235, 230);
|
||||
}
|
||||
/* Import the font using @font-face */
|
||||
@font-face {
|
||||
font-family: 'Calistoga';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('/clay/fonts/Calistoga-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'Quicksand';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url('/clay/fonts/Quicksand-Semibold.ttf') format('truetype');
|
||||
}
|
||||
|
||||
body > canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
div, a, img {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-webkit-backface-visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.text {
|
||||
pointer-events: all;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
/* TODO special exception for text selection in debug tools */
|
||||
[id='2067877626'] > * {
|
||||
pointer-events: none !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<script type="module">
|
||||
const CLAY_RENDER_COMMAND_TYPE_NONE = 0;
|
||||
const CLAY_RENDER_COMMAND_TYPE_RECTANGLE = 1;
|
||||
const CLAY_RENDER_COMMAND_TYPE_BORDER = 2;
|
||||
const CLAY_RENDER_COMMAND_TYPE_TEXT = 3;
|
||||
const CLAY_RENDER_COMMAND_TYPE_IMAGE = 4;
|
||||
const CLAY_RENDER_COMMAND_TYPE_SCISSOR_START = 5;
|
||||
const CLAY_RENDER_COMMAND_TYPE_SCISSOR_END = 6;
|
||||
const CLAY_RENDER_COMMAND_TYPE_CUSTOM = 7;
|
||||
const GLOBAL_FONT_SCALING_FACTOR = 0.8;
|
||||
let renderCommandSize = 0;
|
||||
let scratchSpaceAddress = 8;
|
||||
let heapSpaceAddress = 0;
|
||||
let memoryDataView;
|
||||
let textDecoder = new TextDecoder("utf-8");
|
||||
let previousFrameTime;
|
||||
let fontsById = [
|
||||
'Quicksand',
|
||||
'Calistoga',
|
||||
'Quicksand',
|
||||
'Quicksand',
|
||||
'Quicksand',
|
||||
];
|
||||
let elementCache = {};
|
||||
let imageCache = {};
|
||||
let colorDefinition = { type: 'struct', members: [
|
||||
{name: 'r', type: 'float' },
|
||||
{name: 'g', type: 'float' },
|
||||
{name: 'b', type: 'float' },
|
||||
{name: 'a', type: 'float' },
|
||||
]};
|
||||
let stringDefinition = { type: 'struct', members: [
|
||||
{name: 'length', type: 'uint32_t' },
|
||||
{name: 'chars', type: 'uint32_t' },
|
||||
]};
|
||||
let borderDefinition = { type: 'struct', members: [
|
||||
{name: 'width', type: 'uint32_t'},
|
||||
{name: 'color', ...colorDefinition},
|
||||
]};
|
||||
let cornerRadiusDefinition = { type: 'struct', members: [
|
||||
{name: 'topLeft', type: 'float'},
|
||||
{name: 'topRight', type: 'float'},
|
||||
{name: 'bottomLeft', type: 'float'},
|
||||
{name: 'bottomRight', type: 'float'},
|
||||
]};
|
||||
let rectangleConfigDefinition = { name: 'rectangle', type: 'struct', members: [
|
||||
{ name: 'color', ...colorDefinition },
|
||||
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
||||
{ name: 'link', ...stringDefinition },
|
||||
{ name: 'cursorPointer', type: 'uint8_t' },
|
||||
]};
|
||||
let borderConfigDefinition = { name: 'text', type: 'struct', members: [
|
||||
{ name: 'left', ...borderDefinition },
|
||||
{ name: 'right', ...borderDefinition },
|
||||
{ name: 'top', ...borderDefinition },
|
||||
{ name: 'bottom', ...borderDefinition },
|
||||
{ name: 'betweenChildren', ...borderDefinition },
|
||||
{ name: 'cornerRadius', ...cornerRadiusDefinition }
|
||||
]};
|
||||
let textConfigDefinition = { name: 'text', type: 'struct', members: [
|
||||
{ name: 'textColor', ...colorDefinition },
|
||||
{ name: 'fontId', type: 'uint16_t' },
|
||||
{ name: 'fontSize', type: 'uint16_t' },
|
||||
{ name: 'letterSpacing', type: 'uint16_t' },
|
||||
{ name: 'lineSpacing', type: 'uint16_t' },
|
||||
{ name: 'wrapMode', type: 'uint32_t' },
|
||||
{ name: 'disablePointerEvents', type: 'uint8_t' }
|
||||
]};
|
||||
let scrollConfigDefinition = { name: 'text', type: 'struct', members: [
|
||||
{ name: 'horizontal', type: 'bool' },
|
||||
{ name: 'vertical', type: 'bool' },
|
||||
]};
|
||||
let imageConfigDefinition = { name: 'image', type: 'struct', members: [
|
||||
{ name: 'imageData', type: 'uint32_t' },
|
||||
{ name: 'sourceDimensions', type: 'struct', members: [
|
||||
{ name: 'width', type: 'float' },
|
||||
{ name: 'height', type: 'float' },
|
||||
]},
|
||||
{ name: 'sourceURL', ...stringDefinition }
|
||||
]};
|
||||
let customConfigDefinition = { name: 'custom', type: 'struct', members: [
|
||||
{ name: 'customData', type: 'uint32_t' },
|
||||
]}
|
||||
let renderCommandDefinition = {
|
||||
name: 'CLay_RenderCommand',
|
||||
type: 'struct',
|
||||
members: [
|
||||
{ name: 'boundingBox', type: 'struct', members: [
|
||||
{ name: 'x', type: 'float' },
|
||||
{ name: 'y', type: 'float' },
|
||||
{ name: 'width', type: 'float' },
|
||||
{ name: 'height', type: 'float' },
|
||||
]},
|
||||
{ name: 'config', type: 'uint32_t'},
|
||||
{ name: 'text', ...stringDefinition },
|
||||
{ name: 'id', type: 'uint32_t' },
|
||||
{ name: 'commandType', type: 'uint32_t', },
|
||||
]
|
||||
};
|
||||
|
||||
function getStructTotalSize(definition) {
|
||||
switch(definition.type) {
|
||||
case 'union':
|
||||
case 'struct': {
|
||||
let totalSize = 0;
|
||||
for (const member of definition.members) {
|
||||
let result = getStructTotalSize(member);
|
||||
if (definition.type === 'struct') {
|
||||
totalSize += result;
|
||||
} else {
|
||||
totalSize = Math.max(totalSize, result);
|
||||
}
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
case 'float': return 4;
|
||||
case 'uint32_t': return 4;
|
||||
case 'int32_t': return 4;
|
||||
case 'uint16_t': return 2;
|
||||
case 'uint8_t': return 1;
|
||||
case 'bool': return 1;
|
||||
default: {
|
||||
throw "Unimplemented C data type " + definition.type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readStructAtAddress(address, definition) {
|
||||
switch(definition.type) {
|
||||
case 'union':
|
||||
case 'struct': {
|
||||
let struct = { __size: 0 };
|
||||
for (const member of definition.members) {
|
||||
let result = readStructAtAddress(address, member);
|
||||
struct[member.name] = result;
|
||||
if (definition.type === 'struct') {
|
||||
struct.__size += result.__size;
|
||||
address += result.__size;
|
||||
} else {
|
||||
struct.__size = Math.max(struct.__size, result.__size);
|
||||
}
|
||||
}
|
||||
return struct;
|
||||
}
|
||||
case 'float': return { value: memoryDataView.getFloat32(address, true), __size: 4 };
|
||||
case 'uint32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
|
||||
case 'int32_t': return { value: memoryDataView.getUint32(address, true), __size: 4 };
|
||||
case 'uint16_t': return { value: memoryDataView.getUint16(address, true), __size: 2 };
|
||||
case 'uint8_t': return { value: memoryDataView.getUint8(address, true), __size: 1 };
|
||||
case 'bool': return { value: memoryDataView.getUint8(address, true), __size: 1 };
|
||||
default: {
|
||||
throw "Unimplemented C data type " + definition.type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getTextDimensions(text, font) {
|
||||
// re-use canvas object for better performance
|
||||
window.canvasContext.font = font;
|
||||
let metrics = window.canvasContext.measureText(text);
|
||||
return { width: metrics.width, height: metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent };
|
||||
}
|
||||
|
||||
function createMainArena(arenaStructAddress, arenaMemoryAddress) {
|
||||
let memorySize = instance.exports.Clay_MinMemorySize();
|
||||
// Last arg is address to store return value
|
||||
instance.exports.Clay_CreateArenaWithCapacityAndMemory(arenaStructAddress, memorySize, arenaMemoryAddress);
|
||||
}
|
||||
async function init() {
|
||||
await Promise.all(fontsById.map(f => document.fonts.load(`12px "${f}"`)));
|
||||
window.htmlRoot = document.body.appendChild(document.createElement('div'));
|
||||
window.canvasRoot = document.body.appendChild(document.createElement('canvas'));
|
||||
window.canvasContext = window.canvasRoot.getContext("2d");
|
||||
window.mousePositionXThisFrame = 0;
|
||||
window.mousePositionYThisFrame = 0;
|
||||
window.mouseWheelXThisFrame = 0;
|
||||
window.mouseWheelYThisFrame = 0;
|
||||
window.touchDown = false;
|
||||
window.arrowKeyDownPressedThisFrame = false;
|
||||
window.arrowKeyUpPressedThisFrame = false;
|
||||
let zeroTimeout = null;
|
||||
document.addEventListener("wheel", (event) => {
|
||||
window.mouseWheelXThisFrame = event.deltaX * -0.1;
|
||||
window.mouseWheelYThisFrame = event.deltaY * -0.1;
|
||||
clearTimeout(zeroTimeout);
|
||||
zeroTimeout = setTimeout(() => {
|
||||
window.mouseWheelXThisFrame = 0;
|
||||
window.mouseWheelYThisFrame = 0;
|
||||
}, 10);
|
||||
});
|
||||
|
||||
function handleTouch (event) {
|
||||
if (event.touches.length === 1) {
|
||||
window.touchDown = true;
|
||||
let target = event.target;
|
||||
let scrollTop = 0;
|
||||
let scrollLeft = 0;
|
||||
let activeRendererIndex = memoryDataView.getUint32(instance.exports.ACTIVE_RENDERER_INDEX.value, true);
|
||||
while (activeRendererIndex !== 1 && target) {
|
||||
scrollLeft += target.scrollLeft;
|
||||
scrollTop += target.scrollTop;
|
||||
target = target.parentElement;
|
||||
}
|
||||
window.mousePositionXThisFrame = event.changedTouches[0].pageX + scrollLeft;
|
||||
window.mousePositionYThisFrame = event.changedTouches[0].pageY + scrollTop;
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("touchstart", handleTouch);
|
||||
document.addEventListener("touchmove", handleTouch);
|
||||
document.addEventListener("touchend", () => {
|
||||
window.touchDown = false;
|
||||
window.mousePositionXThisFrame = 0;
|
||||
window.mousePositionYThisFrame = 0;
|
||||
})
|
||||
|
||||
document.addEventListener("mousemove", (event) => {
|
||||
let target = event.target;
|
||||
let scrollTop = 0;
|
||||
let scrollLeft = 0;
|
||||
let activeRendererIndex = memoryDataView.getUint32(instance.exports.ACTIVE_RENDERER_INDEX.value, true);
|
||||
while (activeRendererIndex !== 1 && target) {
|
||||
scrollLeft += target.scrollLeft;
|
||||
scrollTop += target.scrollTop;
|
||||
target = target.parentElement;
|
||||
}
|
||||
window.mousePositionXThisFrame = event.x + scrollLeft;
|
||||
window.mousePositionYThisFrame = event.y + scrollTop;
|
||||
});
|
||||
|
||||
document.addEventListener("mousedown", (event) => {
|
||||
window.mouseDown = true;
|
||||
window.mouseDownThisFrame = true;
|
||||
});
|
||||
|
||||
document.addEventListener("mouseup", (event) => {
|
||||
window.mouseDown = false;
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "ArrowDown") {
|
||||
window.arrowKeyDownPressedThisFrame = true;
|
||||
}
|
||||
if (event.key === "ArrowUp") {
|
||||
window.arrowKeyUpPressedThisFrame = true;
|
||||
}
|
||||
if (event.key === "d") {
|
||||
window.dKeyPressedThisFrame = true;
|
||||
}
|
||||
});
|
||||
|
||||
const importObject = {
|
||||
clay: {
|
||||
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig) => {
|
||||
let stringLength = memoryDataView.getUint32(textToMeasure, true);
|
||||
let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true);
|
||||
let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition);
|
||||
let textDecoder = new TextDecoder("utf-8");
|
||||
let text = textDecoder.decode(memoryDataView.buffer.slice(pointerToString, pointerToString + stringLength));
|
||||
let sourceDimensions = getTextDimensions(text, `${Math.round(textConfig.fontSize.value * GLOBAL_FONT_SCALING_FACTOR)}px ${fontsById[textConfig.fontId.value]}`);
|
||||
memoryDataView.setFloat32(addressOfDimensions, sourceDimensions.width, true);
|
||||
memoryDataView.setFloat32(addressOfDimensions + 4, sourceDimensions.height, true);
|
||||
},
|
||||
queryScrollOffsetFunction: (addressOfOffset, elementId) => {
|
||||
let container = document.getElementById(elementId.toString());
|
||||
if (container) {
|
||||
memoryDataView.setFloat32(addressOfOffset, -container.scrollLeft, true);
|
||||
memoryDataView.setFloat32(addressOfOffset + 4, -container.scrollTop, true);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
const { instance } = await WebAssembly.instantiateStreaming(
|
||||
fetch("/clay/index.wasm"), importObject
|
||||
);
|
||||
memoryDataView = new DataView(new Uint8Array(instance.exports.memory.buffer).buffer);
|
||||
scratchSpaceAddress = instance.exports.__heap_base.value;
|
||||
heapSpaceAddress = instance.exports.__heap_base.value + 1024;
|
||||
let arenaAddress = scratchSpaceAddress + 8;
|
||||
window.instance = instance;
|
||||
createMainArena(arenaAddress, heapSpaceAddress);
|
||||
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
||||
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
||||
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
||||
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
||||
renderLoop();
|
||||
}
|
||||
|
||||
function MemoryIsDifferent(one, two, length) {
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (one[i] !== two[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function renderLoopHTML() {
|
||||
let capacity = memoryDataView.getInt32(scratchSpaceAddress, true);
|
||||
let length = memoryDataView.getInt32(scratchSpaceAddress + 4, true);
|
||||
let arrayOffset = memoryDataView.getUint32(scratchSpaceAddress + 8, true);
|
||||
let scissorStack = [{ nextAllocation: { x: 0, y: 0 }, element: htmlRoot, nextElementIndex: 0 }];
|
||||
let previousId = 0;
|
||||
for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
|
||||
let entireRenderCommandMemory = new Uint32Array(memoryDataView.buffer.slice(arrayOffset, arrayOffset + renderCommandSize));
|
||||
let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
|
||||
let parentElement = scissorStack[scissorStack.length - 1];
|
||||
let element = null;
|
||||
let isMultiConfigElement = previousId === renderCommand.id.value;
|
||||
if (!elementCache[renderCommand.id.value]) {
|
||||
let elementType = 'div';
|
||||
switch (renderCommand.commandType.value) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
if (readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition).link.length.value > 0) {
|
||||
elementType = 'a';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
elementType = 'img'; break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
element = document.createElement(elementType);
|
||||
element.id = renderCommand.id.value;
|
||||
if (renderCommand.commandType.value === CLAY_RENDER_COMMAND_TYPE_SCISSOR_START) {
|
||||
element.style.overflow = 'hidden';
|
||||
}
|
||||
elementCache[renderCommand.id.value] = {
|
||||
exists: true,
|
||||
element: element,
|
||||
previousMemoryCommand: new Uint8Array(0),
|
||||
previousMemoryConfig: new Uint8Array(0),
|
||||
previousMemoryText: new Uint8Array(0)
|
||||
};
|
||||
}
|
||||
|
||||
let elementData = elementCache[renderCommand.id.value];
|
||||
element = elementData.element;
|
||||
if (!isMultiConfigElement && Array.prototype.indexOf.call(parentElement.element.children, element) !== parentElement.nextElementIndex) {
|
||||
if (parentElement.nextElementIndex === 0) {
|
||||
parentElement.element.insertAdjacentElement('afterbegin', element);
|
||||
} else {
|
||||
parentElement.element.childNodes[Math.min(parentElement.nextElementIndex - 1, parentElement.element.childNodes.length - 1)].insertAdjacentElement('afterend', element);
|
||||
}
|
||||
}
|
||||
|
||||
elementData.exists = true;
|
||||
// Don't get me started. Cheaper to compare the render command memory than to update HTML elements
|
||||
let dirty = MemoryIsDifferent(elementData.previousMemoryCommand, entireRenderCommandMemory, renderCommandSize) && !isMultiConfigElement;
|
||||
if (!isMultiConfigElement) {
|
||||
parentElement.nextElementIndex++;
|
||||
}
|
||||
|
||||
previousId = renderCommand.id.value;
|
||||
|
||||
elementData.previousMemoryCommand = entireRenderCommandMemory;
|
||||
let offsetX = scissorStack.length > 0 ? scissorStack[scissorStack.length - 1].nextAllocation.x : 0;
|
||||
let offsetY = scissorStack.length > 0 ? scissorStack[scissorStack.length - 1].nextAllocation.y : 0;
|
||||
if (dirty) {
|
||||
element.style.transform = `translate(${Math.round(renderCommand.boundingBox.x.value - offsetX)}px, ${Math.round(renderCommand.boundingBox.y.value - offsetY)}px)`
|
||||
element.style.width = Math.round(renderCommand.boundingBox.width.value) + 'px';
|
||||
element.style.height = Math.round(renderCommand.boundingBox.height.value) + 'px';
|
||||
}
|
||||
|
||||
// note: commandType is packed to uint8_t and has 3 garbage bytes of padding
|
||||
switch(renderCommand.commandType.value & 0xff) {
|
||||
case (CLAY_RENDER_COMMAND_TYPE_NONE): {
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
|
||||
let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
|
||||
let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
|
||||
memoryDataView.setUint32(0, renderCommand.id.value, true);
|
||||
if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
|
||||
window.location.href = linkContents;
|
||||
}
|
||||
if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
|
||||
break;
|
||||
}
|
||||
if (linkContents.length > 0) {
|
||||
element.href = linkContents;
|
||||
}
|
||||
|
||||
if (linkContents.length > 0 || config.cursorPointer.value) {
|
||||
element.style.pointerEvents = 'all';
|
||||
element.style.cursor = 'pointer';
|
||||
}
|
||||
elementData.previousMemoryConfig = configMemory;
|
||||
let color = config.color;
|
||||
element.style.backgroundColor = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
if (config.cornerRadius.topLeft.value > 0) {
|
||||
element.style.borderTopLeftRadius = config.cornerRadius.topLeft.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.topRight.value > 0) {
|
||||
element.style.borderTopRightRadius = config.cornerRadius.topRight.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.bottomLeft.value > 0) {
|
||||
element.style.borderBottomLeftRadius = config.cornerRadius.bottomLeft.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.bottomRight.value > 0) {
|
||||
element.style.borderBottomRightRadius = config.cornerRadius.bottomRight.value + 'px';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
|
||||
let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
|
||||
if (!dirty && !MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
|
||||
break;
|
||||
}
|
||||
elementData.previousMemoryConfig = configMemory;
|
||||
if (config.left.width.value > 0) {
|
||||
let color = config.left.color;
|
||||
element.style.borderLeft = `${config.left.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
|
||||
}
|
||||
if (config.right.width.value > 0) {
|
||||
let color = config.right.color;
|
||||
element.style.borderRight = `${config.right.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
|
||||
}
|
||||
if (config.top.width.value > 0) {
|
||||
let color = config.top.color;
|
||||
element.style.borderTop = `${config.top.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
|
||||
}
|
||||
if (config.bottom.width.value > 0) {
|
||||
let color = config.bottom.color;
|
||||
element.style.borderBottom = `${config.bottom.width.value}px solid rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`
|
||||
}
|
||||
if (config.cornerRadius.topLeft.value > 0) {
|
||||
element.style.borderTopLeftRadius = config.cornerRadius.topLeft.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.topRight.value > 0) {
|
||||
element.style.borderTopRightRadius = config.cornerRadius.topRight.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.bottomLeft.value > 0) {
|
||||
element.style.borderBottomLeftRadius = config.cornerRadius.bottomLeft.value + 'px';
|
||||
}
|
||||
if (config.cornerRadius.bottomRight.value > 0) {
|
||||
element.style.borderBottomRightRadius = config.cornerRadius.bottomRight.value + 'px';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
|
||||
let configMemory = new Uint8Array(memoryDataView.buffer.slice(renderCommand.config.value, renderCommand.config.value + config.__size));
|
||||
let textContents = renderCommand.text;
|
||||
let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
|
||||
if (MemoryIsDifferent(configMemory, elementData.previousMemoryConfig, config.__size)) {
|
||||
element.className = 'text';
|
||||
let textColor = config.textColor;
|
||||
let fontSize = Math.round(config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR);
|
||||
element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
|
||||
element.style.fontFamily = fontsById[config.fontId.value];
|
||||
element.style.fontSize = fontSize + 'px';
|
||||
element.style.pointerEvents = config.disablePointerEvents.value ? 'none' : 'all';
|
||||
elementData.previousMemoryConfig = configMemory;
|
||||
}
|
||||
if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
|
||||
element.innerHTML = textDecoder.decode(stringContents);
|
||||
}
|
||||
elementData.previousMemoryText = stringContents;
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||
scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
|
||||
let config = readStructAtAddress(renderCommand.config.value, scrollConfigDefinition);
|
||||
if (config.horizontal.value) {
|
||||
element.style.overflowX = 'scroll';
|
||||
element.style.pointerEvents = 'auto';
|
||||
}
|
||||
if (config.vertical.value) {
|
||||
element.style.overflowY = 'scroll';
|
||||
element.style.pointerEvents = 'auto';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
|
||||
scissorStack.splice(scissorStack.length - 1, 1);
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
|
||||
let srcContents = new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value));
|
||||
if (srcContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(srcContents, elementData.previousMemoryText, srcContents.length)) {
|
||||
element.src = textDecoder.decode(srcContents);
|
||||
}
|
||||
elementData.previousMemoryText = srcContents;
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of Object.keys(elementCache)) {
|
||||
if (elementCache[key].exists) {
|
||||
elementCache[key].exists = false;
|
||||
} else {
|
||||
elementCache[key].element.remove();
|
||||
delete elementCache[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderLoopCanvas() {
|
||||
// Note: Rendering to canvas needs to be scaled up by window.devicePixelRatio in both width and height.
|
||||
// e.g. if we're working on a device where devicePixelRatio is 2, we need to render
|
||||
// everything at width^2 x height^2 resolution, then scale back down with css to get the correct pixel density.
|
||||
let capacity = memoryDataView.getUint32(scratchSpaceAddress, true);
|
||||
let length = memoryDataView.getUint32(scratchSpaceAddress + 4, true);
|
||||
let arrayOffset = memoryDataView.getUint32(scratchSpaceAddress + 8, true);
|
||||
window.canvasRoot.width = window.innerWidth * window.devicePixelRatio;
|
||||
window.canvasRoot.height = window.innerHeight * window.devicePixelRatio;
|
||||
window.canvasRoot.style.width = window.innerWidth + 'px';
|
||||
window.canvasRoot.style.height = window.innerHeight + 'px';
|
||||
let ctx = window.canvasContext;
|
||||
let scale = window.devicePixelRatio;
|
||||
for (let i = 0; i < length; i++, arrayOffset += renderCommandSize) {
|
||||
let renderCommand = readStructAtAddress(arrayOffset, renderCommandDefinition);
|
||||
let boundingBox = renderCommand.boundingBox;
|
||||
|
||||
// note: commandType is packed to uint8_t and has 3 garbage bytes of padding
|
||||
switch(renderCommand.commandType.value & 0xff) {
|
||||
case (CLAY_RENDER_COMMAND_TYPE_NONE): {
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_RECTANGLE): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, rectangleConfigDefinition);
|
||||
let color = config.color;
|
||||
ctx.beginPath();
|
||||
window.canvasContext.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
window.canvasContext.roundRect(
|
||||
boundingBox.x.value * scale, // x
|
||||
boundingBox.y.value * scale, // y
|
||||
boundingBox.width.value * scale, // width
|
||||
boundingBox.height.value * scale,
|
||||
[config.cornerRadius.topLeft.value * scale, config.cornerRadius.topRight.value * scale, config.cornerRadius.bottomRight.value * scale, config.cornerRadius.bottomLeft.value * scale]) // height;
|
||||
ctx.fill();
|
||||
ctx.closePath();
|
||||
// Handle link clicks
|
||||
let linkContents = config.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.link.chars.value, config.link.chars.value + config.link.length.value))) : 0;
|
||||
memoryDataView.setUint32(0, renderCommand.id.value, true);
|
||||
if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
|
||||
window.location.href = linkContents;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_BORDER): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, borderConfigDefinition);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(boundingBox.x.value * scale, boundingBox.y.value * scale);
|
||||
// Top Left Corner
|
||||
if (config.cornerRadius.topLeft.value > 0) {
|
||||
let lineWidth = config.top.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale);
|
||||
let color = config.top.color;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, config.cornerRadius.topLeft.value * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Top border
|
||||
if (config.top.width.value > 0) {
|
||||
let lineWidth = config.top.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
let color = config.top.color;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.moveTo((boundingBox.x.value + config.cornerRadius.topLeft.value + halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
|
||||
ctx.lineTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Top Right Corner
|
||||
if (config.cornerRadius.topRight.value > 0) {
|
||||
let lineWidth = config.top.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.moveTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.topRight.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale);
|
||||
let color = config.top.color;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale, config.cornerRadius.topRight.value * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Right border
|
||||
if (config.right.width.value > 0) {
|
||||
let color = config.right.color;
|
||||
let lineWidth = config.right.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.topRight.value + halfLineWidth) * scale);
|
||||
ctx.lineTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.topRight.value - halfLineWidth) * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Bottom Right Corner
|
||||
if (config.cornerRadius.bottomRight.value > 0) {
|
||||
let color = config.top.color;
|
||||
let lineWidth = config.top.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.moveTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale);
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.arcTo((boundingBox.x.value + boundingBox.width.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale, (boundingBox.x.value + boundingBox.width.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale, config.cornerRadius.bottomRight.value * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Bottom Border
|
||||
if (config.bottom.width.value > 0) {
|
||||
let color = config.bottom.color;
|
||||
let lineWidth = config.bottom.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
|
||||
ctx.lineTo((boundingBox.x.value + boundingBox.width.value - config.cornerRadius.bottomRight.value - halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Bottom Left Corner
|
||||
if (config.cornerRadius.bottomLeft.value > 0) {
|
||||
let color = config.bottom.color;
|
||||
let lineWidth = config.bottom.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.moveTo((boundingBox.x.value + config.cornerRadius.bottomLeft.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale);
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.arcTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - halfLineWidth) * scale, (boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomLeft.value - halfLineWidth) * scale, config.cornerRadius.bottomLeft.value * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
// Left Border
|
||||
if (config.left.width.value > 0) {
|
||||
let color = config.left.color;
|
||||
let lineWidth = config.left.width.value;
|
||||
let halfLineWidth = lineWidth / 2;
|
||||
ctx.lineWidth = lineWidth * scale;
|
||||
ctx.strokeStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.moveTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + boundingBox.height.value - config.cornerRadius.bottomLeft.value - halfLineWidth) * scale);
|
||||
ctx.lineTo((boundingBox.x.value + halfLineWidth) * scale, (boundingBox.y.value + config.cornerRadius.bottomRight.value + halfLineWidth) * scale);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.closePath();
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, textConfigDefinition);
|
||||
let textContents = renderCommand.text;
|
||||
let stringContents = new Uint8Array(memoryDataView.buffer.slice(textContents.chars.value, textContents.chars.value + textContents.length.value));
|
||||
let fontSize = config.fontSize.value * GLOBAL_FONT_SCALING_FACTOR * scale;
|
||||
ctx.font = `${fontSize}px ${fontsById[config.fontId.value]}`;
|
||||
let color = config.textColor;
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillStyle = `rgba(${color.r.value}, ${color.g.value}, ${color.b.value}, ${color.a.value / 255})`;
|
||||
ctx.fillText(textDecoder.decode(stringContents), boundingBox.x.value * scale, (boundingBox.y.value + boundingBox.height.value / 2 + 1) * scale);
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||
window.canvasContext.save();
|
||||
window.canvasContext.beginPath();
|
||||
window.canvasContext.rect(boundingBox.x.value * scale, boundingBox.y.value * scale, boundingBox.width.value * scale, boundingBox.height.value * scale);
|
||||
window.canvasContext.clip();
|
||||
window.canvasContext.closePath();
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_END): {
|
||||
window.canvasContext.restore();
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_IMAGE): {
|
||||
let config = readStructAtAddress(renderCommand.config.value, imageConfigDefinition);
|
||||
let src = textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(config.sourceURL.chars.value, config.sourceURL.chars.value + config.sourceURL.length.value)));
|
||||
if (!imageCache[src]) {
|
||||
imageCache[src] = {
|
||||
image: new Image(),
|
||||
loaded: false,
|
||||
}
|
||||
imageCache[src].image.onload = () => imageCache[src].loaded = true;
|
||||
imageCache[src].image.src = src;
|
||||
} else if (imageCache[src].loaded) {
|
||||
ctx.drawImage(imageCache[src].image, boundingBox.x.value * scale, boundingBox.y.value * scale, boundingBox.width.value * scale, boundingBox.height.value * scale);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_CUSTOM): break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderLoop(currentTime) {
|
||||
const elapsed = currentTime - previousFrameTime;
|
||||
previousFrameTime = currentTime;
|
||||
let activeRendererIndex = memoryDataView.getUint32(instance.exports.ACTIVE_RENDERER_INDEX.value, true);
|
||||
if (activeRendererIndex === 0) {
|
||||
instance.exports.UpdateDrawFrame(scratchSpaceAddress, window.innerWidth, window.innerHeight, 0, 0, window.mousePositionXThisFrame, window.mousePositionYThisFrame, window.touchDown, window.mouseDown, 0, 0, window.dKeyPressedThisFrame, elapsed / 1000);
|
||||
} else {
|
||||
instance.exports.UpdateDrawFrame(scratchSpaceAddress, window.innerWidth, window.innerHeight, window.mouseWheelXThisFrame, window.mouseWheelYThisFrame, window.mousePositionXThisFrame, window.mousePositionYThisFrame, window.touchDown, window.mouseDown, window.arrowKeyDownPressedThisFrame, window.arrowKeyUpPressedThisFrame, window.dKeyPressedThisFrame, elapsed / 1000);
|
||||
}
|
||||
let rendererChanged = activeRendererIndex !== window.previousActiveRendererIndex;
|
||||
switch (activeRendererIndex) {
|
||||
case 0: {
|
||||
renderLoopHTML();
|
||||
if (rendererChanged) {
|
||||
window.htmlRoot.style.display = 'block';
|
||||
window.canvasRoot.style.display = 'none';
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
renderLoopCanvas();
|
||||
if (rendererChanged) {
|
||||
window.htmlRoot.style.display = 'none';
|
||||
window.canvasRoot.style.display = 'block';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
window.previousActiveRendererIndex = activeRendererIndex;
|
||||
requestAnimationFrame(renderLoop);
|
||||
window.mouseDownThisFrame = false;
|
||||
window.arrowKeyUpPressedThisFrame = false;
|
||||
window.arrowKeyDownPressedThisFrame = false;
|
||||
window.dKeyPressedThisFrame = false;
|
||||
}
|
||||
init();
|
||||
</script>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
BIN
examples/clay-official-website/build/clay/index.wasm
Executable file
@ -165,7 +165,7 @@ Clay_Color ColorLerp(Clay_Color a, Clay_Color b, float amount) {
|
||||
Clay_String LOREM_IPSUM_TEXT = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
|
||||
|
||||
void HighPerformancePageDesktop(float lerpValue) {
|
||||
CLAY(CLAY_ID("PerformanceDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
|
||||
CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
|
||||
CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
|
||||
CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
|
||||
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
|
||||
@ -187,7 +187,7 @@ void HighPerformancePageDesktop(float lerpValue) {
|
||||
}
|
||||
|
||||
void HighPerformancePageMobile(float lerpValue) {
|
||||
CLAY(CLAY_ID("PerformanceMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
|
||||
CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
|
||||
CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
|
||||
CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
|
||||
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
|
||||
@ -390,7 +390,11 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
|
||||
windowWidth = width;
|
||||
windowHeight = height;
|
||||
Clay_SetLayoutDimensions((Clay_Dimensions) { width, height });
|
||||
if (deltaTime == deltaTime) { // NaN propagation can cause pain here
|
||||
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
|
||||
Clay_LayoutElementHashMapItem *perfPage = Clay__GetHashMapItem(Clay_GetElementId(CLAY_STRING("PerformancePageOuter")).id);
|
||||
// NaN propagation can cause pain here
|
||||
float perfPageYOffset = perfPage->boundingBox.y + scrollContainerData.scrollPosition->y;
|
||||
if (deltaTime == deltaTime && perfPageYOffset < height && perfPageYOffset + perfPage->boundingBox.height > 0) {
|
||||
animationLerpValue += deltaTime;
|
||||
if (animationLerpValue > 1) {
|
||||
animationLerpValue -= 2;
|
||||
@ -413,12 +417,10 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
|
||||
}
|
||||
|
||||
if (isMouseDown && !scrollbarData.mouseDown && Clay_PointerOver(Clay_GetElementId(CLAY_STRING("ScrollBar")))) {
|
||||
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
|
||||
scrollbarData.clickOrigin = (Clay_Vector2) { mousePositionX, mousePositionY };
|
||||
scrollbarData.positionOrigin = *scrollContainerData.scrollPosition;
|
||||
scrollbarData.mouseDown = true;
|
||||
} else if (scrollbarData.mouseDown) {
|
||||
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
|
||||
if (scrollContainerData.contentDimensions.height > 0) {
|
||||
Clay_Vector2 ratio = (Clay_Vector2) {
|
||||
scrollContainerData.contentDimensions.width / scrollContainerData.scrollContainerDimensions.width,
|
||||
@ -434,12 +436,10 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
|
||||
}
|
||||
|
||||
if (arrowKeyDownPressedThisFrame) {
|
||||
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
|
||||
if (scrollContainerData.contentDimensions.height > 0) {
|
||||
scrollContainerData.scrollPosition->y = scrollContainerData.scrollPosition->y - 50;
|
||||
}
|
||||
} else if (arrowKeyUpPressedThisFrame) {
|
||||
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
|
||||
if (scrollContainerData.contentDimensions.height > 0) {
|
||||
scrollContainerData.scrollPosition->y = scrollContainerData.scrollPosition->y + 50;
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ add_executable(clay_examples_cpp_project_example main.cpp)
|
||||
|
||||
target_include_directories(clay_examples_cpp_project_example PUBLIC .)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall -Wno-error=missing-braces")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
||||
|