mirror of
https://github.com/nicbarker/clay.git
synced 2025-05-17 15:58:05 +00:00
Compare commits
14 Commits
77be6d6ae3
...
86cadd6651
Author | SHA1 | Date | |
---|---|---|---|
|
86cadd6651 | ||
|
4f8957d5d2 | ||
|
5009146c65 | ||
|
865b06d386 | ||
|
12319fc240 | ||
|
2d7d5bc082 | ||
|
02bce89d17 | ||
|
b5b086af13 | ||
|
5571c00a21 | ||
|
4ee501019c | ||
|
1fa8684e47 | ||
|
feead45f3e | ||
|
766325c395 | ||
|
5afdf3f8c9 |
2
.github/workflows/cmake-multi-platform.yml
vendored
2
.github/workflows/cmake-multi-platform.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
||||
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache
|
||||
uses: actions/cache@v4.0.2
|
||||
uses: actions/cache@v4.2.0
|
||||
with:
|
||||
# A list of files, directories, and wildcard patterns to cache and restore
|
||||
path: "/home/runner/work/clay/clay/build/_deps"
|
||||
|
67
README.md
67
README.md
@ -89,7 +89,7 @@ int main() {
|
||||
CLAY({
|
||||
.id = CLAY_ID("SideBar"),
|
||||
.layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16 },
|
||||
.backgroundColor = COLOR_LIGHT }
|
||||
.backgroundColor = COLOR_LIGHT
|
||||
}) {
|
||||
CLAY({ .id = CLAY_ID("ProfilePictureOuter"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }, .backgroundColor = COLOR_RED }) {
|
||||
CLAY({ .id = CLAY_ID("ProfilePicture"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}, .image = { .imageData = &profilePicture, .sourceDimensions = {60, 60} } }) {}
|
||||
@ -474,6 +474,7 @@ Clay supports C preprocessor directives to modulate functionality at compile tim
|
||||
The supported directives are:
|
||||
|
||||
- `CLAY_WASM` - Required when targeting Web Assembly.
|
||||
- `CLAY_DLL` - Required when creating a .Dll file.
|
||||
|
||||
### Bindings for non C
|
||||
|
||||
@ -896,18 +897,12 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_
|
||||
|
||||
### CLAY_ID
|
||||
|
||||
**Usage**
|
||||
|
||||
`CLAY(CLAY_ID(char* idString)) {}`
|
||||
|
||||
**Lifecycle**
|
||||
|
||||
`Clay_BeginLayout()` -> `CLAY(` -> `CLAY_ID()` -> `)` -> `Clay_EndLayout()`
|
||||
|
||||
**Notes**
|
||||
`Clay_ElementId CLAY_ID(STRING_LITERAL idString)`
|
||||
|
||||
**CLAY_ID()** is used to generate and attach a [Clay_ElementId](#clay_elementid) to a layout element during declaration.
|
||||
|
||||
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SID](#clay_sid).
|
||||
|
||||
To regenerate the same ID outside of layout declaration when using utility functions such as [Clay_PointerOver](#clay_pointerover), use the [Clay_GetElementId](#clay_getelementid) function.
|
||||
|
||||
**Examples**
|
||||
@ -930,11 +925,31 @@ if (buttonIsHovered && leftMouseButtonPressed) {
|
||||
|
||||
---
|
||||
|
||||
### CLAY_SID()
|
||||
|
||||
`Clay_ElementId CLAY_SID(Clay_String idString)`
|
||||
|
||||
A version of [CLAY_ID](#clay_id) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_IDI()
|
||||
|
||||
`Clay_ElementId CLAY_IDI(char *label, int32_t index)`
|
||||
`Clay_ElementId CLAY_IDI(STRING_LITERAL idString, int32_t 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.
|
||||
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.
|
||||
|
||||
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SIDI](#clay_sidi).
|
||||
|
||||
---
|
||||
|
||||
### CLAY_SIDI()
|
||||
|
||||
`Clay_ElementId CLAY_SIDI(Clay_String idString, int32_t index)`
|
||||
|
||||
A version of [CLAY_IDI](#clay_idi) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
|
||||
|
||||
---
|
||||
|
||||
@ -942,7 +957,7 @@ An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_ele
|
||||
|
||||
**Usage**
|
||||
|
||||
`CLAY(CLAY_ID_LOCAL(char* idString)) {}`
|
||||
`Clay_ElementId CLAY_ID_LOCAL(STRING_LITERAL idString)`
|
||||
|
||||
**Lifecycle**
|
||||
|
||||
@ -956,6 +971,8 @@ Unlike [CLAY_ID](#clay_id) which needs to be globally unique, a local ID is base
|
||||
|
||||
As a result, local id is suitable for use in reusable components and loops.
|
||||
|
||||
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SID_LOCAL](#clay_sid_local).
|
||||
|
||||
**Examples**
|
||||
|
||||
```C
|
||||
@ -975,11 +992,31 @@ for (int i = 0; i < headerButtons.length; i++) {
|
||||
|
||||
---
|
||||
|
||||
### CLAY_SID_LOCAL()
|
||||
|
||||
`Clay_ElementId CLAY_SID_LOCAL(Clay_String idString)`
|
||||
|
||||
A version of [CLAY_ID_LOCAL](#clay_id_local) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
|
||||
|
||||
---
|
||||
|
||||
### CLAY_IDI_LOCAL()
|
||||
|
||||
`Clay_ElementId CLAY_IDI_LOCAL(char *label, int32_t index)`
|
||||
`Clay_ElementId CLAY_IDI_LOCAL(STRING_LITERAL idString, int32_t index)`
|
||||
|
||||
An offset version of [CLAY_ID_LOCAL](#clay_local_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.
|
||||
An offset version of [CLAY_ID_LOCAL](#clay_local_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.
|
||||
|
||||
Note this macro only works with String literals and won't compile if used with a `char*` variable. To use a heap allocated `char*` string as an ID, use [CLAY_SIDI_LOCAL](#clay_sidi_local).
|
||||
|
||||
---
|
||||
|
||||
### CLAY_SIDI_LOCAL()
|
||||
|
||||
`Clay_ElementId CLAY_SIDI_LOCAL(Clay_String idString, int32_t index)`
|
||||
|
||||
A version of [CLAY_IDI_LOCAL](#clay_idi_local) that can be used with heap allocated `char *` data. The underlying `char` data will not be copied internally and should live until at least the next frame.
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
### Odin Language Bindings
|
||||
|
||||
This directory contains bindings for the [Odin](odin-lang.org) programming language, as well as an example implementation of the [clay website](https://nicbarker.com/clay) in Odin.
|
||||
This directory contains bindings for the [Odin](odin-lang.org) programming language, as well as an example implementation of the [Clay website](https://nicbarker.com/clay) in Odin.
|
||||
|
||||
Special thanks to
|
||||
|
||||
@ -8,21 +8,21 @@ Special thanks to
|
||||
- [Dudejoe870](https://github.com/Dudejoe870)
|
||||
- MrStevns from the Odin Discord server
|
||||
|
||||
If you haven't taken a look at the [full documentation for clay](https://github.com/nicbarker/clay/blob/main/README.md), it's recommended that you take a look there first to familiarise yourself with the general concepts. This README is abbreviated and applies to using clay in Odin specifically.
|
||||
|
||||
The **most notable difference** between the C API and the Odin bindings is the use of if statements to create the scope for declaring child elements. When using the equivalent of the [Element Macros](https://github.com/nicbarker/clay/blob/main/README.md#element-macros):
|
||||
If you haven't taken a look at the [full documentation for Clay](https://github.com/nicbarker/clay/blob/main/README.md), it's recommended that you take a look there first to familiarise yourself with the general concepts. This README is abbreviated and applies to using Clay in Odin specifically.
|
||||
|
||||
The **most notable difference** between the C API and the Odin bindings is the use of `if` statements to create the scope for declaring child elements, when using the equivalent of the [Element Macros](https://github.com/nicbarker/clay/blob/main/README.md#element-macros):
|
||||
```C
|
||||
// C form of element macros
|
||||
CLAY_RECTANGLE(CLAY_ID("SideBar"), CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW() }, .padding = {16, 16}), CLAY_RECTANGLE_CONFIG(.color = COLOR_LIGHT), {
|
||||
// Child elements here
|
||||
});
|
||||
// Define an element with 16px of x and y padding
|
||||
CLAY({ .id = CLAY_ID("Outer"), .layout = { .padding = CLAY_PADDING_ALL(16) } }) {
|
||||
// Child elements here
|
||||
}
|
||||
```
|
||||
|
||||
```Odin
|
||||
// Odin form of element macros
|
||||
if clay.Rectangle(clay.ID("SideBar"), clay.Layout({ layoutDirection = .TOP_TO_BOTTOM, sizing = { width = clay.SizingFixed(300), height = clay.SizingGrow({}) }, padding = {16, 16} }), clay.RectangleConfig({ color = COLOR_LIGHT })) {
|
||||
// Child elements here
|
||||
if clay.UI()({ id = clay.ID("Outer"), layout = { padding = clay.PaddingAll(16) }}) {
|
||||
// Child elements here
|
||||
}
|
||||
```
|
||||
|
||||
@ -34,111 +34,170 @@ if clay.Rectangle(clay.ID("SideBar"), clay.Layout({ layoutDirection = .TOP_TO_BO
|
||||
import clay "clay-odin"
|
||||
```
|
||||
|
||||
2. Ask clay for how much static memory it needs using [clay.MinMemorySize()](https://github.com/nicbarker/clay/blob/main/README.md#clay_minmemorysize), create an Arena for it to use with [clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)](https://github.com/nicbarker/clay/blob/main/README.md#clay_createarenawithcapacityandmemory), and initialize it with [clay.Initialize(arena)](https://github.com/nicbarker/clay/blob/main/README.md#clay_initialize).
|
||||
2. Ask Clay for how much static memory it needs using [clay.MinMemorySize()](https://github.com/nicbarker/clay/blob/main/README.md#clay_minmemorysize), create an Arena for it to use with [clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)](https://github.com/nicbarker/clay/blob/main/README.md#clay_createarenawithcapacityandmemory), and initialize it with [clay.Initialize(clay.Arena, clay.Dimensions, clay.ErrorHandler)](https://github.com/nicbarker/clay/blob/main/README.md#clay_initialize).
|
||||
|
||||
```Odin
|
||||
minMemorySize: u32 = clay.MinMemorySize()
|
||||
memory := make([^]u8, minMemorySize)
|
||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
|
||||
clay.Initialize(arena)
|
||||
error_handler :: proc "c" (errorData: clay.ErrorData) {
|
||||
// Do something with the error data.
|
||||
}
|
||||
|
||||
min_memory_size: u32 = clay.MinMemorySize()
|
||||
memory := make([^]u8, min_memory_size)
|
||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(min_memory_size, memory)
|
||||
clay.Initialize(arena, { width = 1080, height = 720 }, { handler = error_handler })
|
||||
```
|
||||
|
||||
3. Provide a `measureText(text, config)` proc "c" with [clay.SetMeasureTextFunction(function)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setmeasuretextfunction) so that clay can measure and wrap text.
|
||||
3. Provide a `measure_text(text, config)` proc "c" with [clay.SetMeasureTextFunction(function)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setmeasuretextfunction) so that Clay can measure and wrap text.
|
||||
|
||||
```Odin
|
||||
// Example measure text function
|
||||
measureText :: proc "c" (text: ^clay.String, config: ^clay.TextElementConfig) -> clay.Dimensions {
|
||||
// clay.TextElementConfig contains members such as fontId, fontSize, letterSpacing etc
|
||||
measure_text :: proc "c" (
|
||||
text: clay.StringSlice,
|
||||
config: ^clay.TextElementConfig,
|
||||
userData: rawptr,
|
||||
) -> clay.Dimensions {
|
||||
// clay.TextElementConfig contains members such as fontId, fontSize, letterSpacing, etc..
|
||||
// Note: clay.String->chars is not guaranteed to be null terminated
|
||||
return {
|
||||
width = f32(text.length * i32(config.fontSize)),
|
||||
height = f32(config.fontSize),
|
||||
}
|
||||
}
|
||||
|
||||
// Tell clay how to measure text
|
||||
clay.SetMeasureTextFunction(measureText)
|
||||
```
|
||||
|
||||
4. **Optional** - Call [clay.SetPointerPosition(pointerPosition)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setpointerposition) if you want to use mouse interactions.
|
||||
// Tell clay how to measure text
|
||||
clay.SetMeasureTextFunction(measure_text, nil)
|
||||
```
|
||||
|
||||
4. **Optional** - Call [clay.SetPointerState(pointerPosition, isPointerDown)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setpointerstate) if you want to use mouse interactions.
|
||||
|
||||
```Odin
|
||||
// Update internal pointer position for handling mouseover / click / touch events
|
||||
clay.SetPointerPosition(clay.Vector2{ mousePositionX, mousePositionY })
|
||||
clay.SetPointerState(
|
||||
clay.Vector2 { mouse_pos_x, mouse_pos_y },
|
||||
is_mouse_down,
|
||||
)
|
||||
```
|
||||
|
||||
5. Call [clay.BeginLayout(screenWidth, screenHeight)](https://github.com/nicbarker/clay/blob/main/README.md#clay_beginlayout) and declare your layout using the provided macros.
|
||||
5. Call [clay.BeginLayout()](https://github.com/nicbarker/clay/blob/main/README.md#clay_beginlayout) and declare your layout using the provided macros.
|
||||
|
||||
```Odin
|
||||
// Define some colors.
|
||||
COLOR_LIGHT :: clay.Color{224, 215, 210, 255}
|
||||
COLOR_RED :: clay.Color{168, 66, 28, 255}
|
||||
COLOR_ORANGE :: clay.Color{225, 138, 50, 255}
|
||||
COLOR_BLACK :: clay.Color{0, 0, 0, 255}
|
||||
|
||||
// Layout config is just a struct that can be declared statically, or inline
|
||||
sidebarItemLayout := clay.LayoutConfig {
|
||||
sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(50)},
|
||||
sidebar_item_layout := clay.LayoutConfig {
|
||||
sizing = {
|
||||
width = clay.SizingGrow({}),
|
||||
height = clay.SizingFixed(50)
|
||||
},
|
||||
}
|
||||
|
||||
// Re-useable components are just normal functions
|
||||
SidebarItemComponent :: proc(index: u32) {
|
||||
if clay.Rectangle(clay.ID("SidebarBlob", index), &sidebarItemLayout, clay.RectangleConfig({color = COLOR_ORANGE})) {}
|
||||
// Re-useable components are just normal procs.
|
||||
sidebar_item_component :: proc(index: u32) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("SidebarBlob", index),
|
||||
layout = sidebar_item_layout,
|
||||
backgroundColor = COLOR_ORANGE,
|
||||
}) {}
|
||||
}
|
||||
|
||||
// An example function to begin the "root" of your layout tree
|
||||
CreateLayout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
||||
clay.BeginLayout(windowWidth, windowHeight)
|
||||
// An example function to create your layout tree
|
||||
create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
||||
// Begin constructing the layout.
|
||||
clay.BeginLayout()
|
||||
|
||||
// An example of laying out a UI with a fixed width sidebar and flexible width main content
|
||||
// NOTE: To create a scope for child components, the Odin api uses `if` with components that have children
|
||||
if clay.Rectangle(
|
||||
clay.ID("OuterContainer"),
|
||||
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
|
||||
clay.RectangleConfig({color = {250, 250, 255, 255}}),
|
||||
) {
|
||||
if clay.Rectangle(
|
||||
clay.ID("SideBar"),
|
||||
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = clay.SizingFixed(300), height = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
|
||||
clay.RectangleConfig({color = COLOR_LIGHT}),
|
||||
) {
|
||||
if clay.Rectangle(
|
||||
clay.ID("ProfilePictureOuter"),
|
||||
clay.Layout({sizing = {width = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16, childAlignment = {y = .CENTER}}),
|
||||
clay.RectangleConfig({color = COLOR_RED}),
|
||||
) {
|
||||
if clay.Image(
|
||||
clay.ID("ProfilePicture"),
|
||||
clay.Layout({sizing = {width = clay.SizingFixed(60), height = clay.SizingFixed(60)}}),
|
||||
clay.ImageConfig({imageData = &profilePicture, sourceDimensions = {height = 60, width = 60}}),
|
||||
) {}
|
||||
clay.Text(clay.ID("ProfileTitle"), "Clay - UI Library", clay.TextConfig({fontSize = 24, textColor = {255, 255, 255, 255}}))
|
||||
// An example of laying out a UI with a fixed-width sidebar and flexible-width main content
|
||||
// NOTE: To create a scope for child components, the Odin API uses `if` with components that have children
|
||||
if clay.UI()({
|
||||
id = clay.ID("OuterContainer"),
|
||||
layout = {
|
||||
sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
|
||||
padding = { 16, 16, 16, 16 },
|
||||
childGap = 16,
|
||||
},
|
||||
backgroundColor = { 250, 250, 255, 255 },
|
||||
}) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("SideBar"),
|
||||
layout = {
|
||||
layoutDirection = .TopToBottom,
|
||||
sizing = { width = clay.SizingFixed(300), height = clay.SizingGrow({}) },
|
||||
padding = { 16, 16, 16, 16 },
|
||||
childGap = 16,
|
||||
},
|
||||
backgroundColor = COLOR_LIGHT,
|
||||
}) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("ProfilePictureOuter"),
|
||||
layout = {
|
||||
sizing = { width = clay.SizingGrow({}) },
|
||||
padding = { 16, 16, 16, 16 },
|
||||
childGap = 16,
|
||||
childAlignment = { y = .Center },
|
||||
},
|
||||
backgroundColor = COLOR_RED,
|
||||
cornerRadius = { 6, 6, 6, 6 },
|
||||
}) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("ProfilePicture"),
|
||||
layout = {
|
||||
sizing = { width = clay.SizingFixed(60), height = clay.SizingFixed(60) },
|
||||
},
|
||||
image = {
|
||||
imageData = &profile_picture,
|
||||
sourceDimensions = {
|
||||
width = 60,
|
||||
height = 60,
|
||||
},
|
||||
},
|
||||
}) {}
|
||||
|
||||
clay.Text(
|
||||
"Clay - UI Library",
|
||||
clay.TextConfig({ textColor = COLOR_BLACK, fontSize = 16 }),
|
||||
)
|
||||
}
|
||||
|
||||
// Standard Odin code like loops etc work inside components
|
||||
for i in 0..<10 {
|
||||
SidebarItemComponent(i)
|
||||
// Standard Odin code like loops, etc. work inside components.
|
||||
// Here we render 5 sidebar items.
|
||||
for i in u32(0)..<5 {
|
||||
sidebar_item_component(i)
|
||||
}
|
||||
}
|
||||
|
||||
if clay.Rectangle(
|
||||
clay.ID("MainContent"),
|
||||
clay.Layout({sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}}),
|
||||
clay.RectangleConfig({color = COLOR_LIGHT}),
|
||||
) {}
|
||||
if clay.UI()({
|
||||
id = clay.ID("MainContent"),
|
||||
layout = {
|
||||
sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
|
||||
},
|
||||
backgroundColor = COLOR_LIGHT,
|
||||
}) {}
|
||||
}
|
||||
// ...
|
||||
|
||||
// Returns a list of render commands
|
||||
render_commands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout()
|
||||
return render_commands
|
||||
}
|
||||
```
|
||||
|
||||
6. Call [clay.EndLayout(screenWidth, screenHeight)](https://github.com/nicbarker/clay/blob/main/README.md#clay_endlayout) and process the resulting [clay.RenderCommandArray](https://github.com/nicbarker/clay/blob/main/README.md#clay_rendercommandarray) in your choice of renderer.
|
||||
6. Call your layout proc and process the resulting [clay.ClayArray(clay.RenderCommand)](https://github.com/nicbarker/clay/blob/main/README.md#clay_rendercommandarray) in your choice of renderer.
|
||||
|
||||
```Odin
|
||||
renderCommands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout(windowWidth, windowHeight)
|
||||
render_commands := create_layout()
|
||||
|
||||
for i: u32 = 0; i < renderCommands.length; i += 1 {
|
||||
renderCommand := clay.RenderCommandArray_Get(&renderCommands, cast(i32)i)
|
||||
for i in 0..<i32(render_commands.length) {
|
||||
render_command := clay.RenderCommandArray_Get(render_commands, i)
|
||||
|
||||
switch renderCommand.commandType {
|
||||
switch render_command.commandType {
|
||||
case .Rectangle:
|
||||
DrawRectangle(renderCommand.boundingBox, renderCommand.config.rectangleElementConfig.color)
|
||||
DrawRectangle(render_command.boundingBox, render_command.config.rectangleElementConfig.color)
|
||||
// ... Implement handling of other command types
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Please see the [full C documentation for clay](https://github.com/nicbarker/clay/blob/main/README.md) for API details. All public C functions and Macros have Odin binding equivalents, generally of the form `CLAY_RECTANGLE` (C) -> `clay.Rectangle` (Odin)
|
||||
Please see the [full C documentation for Clay](https://github.com/nicbarker/clay/blob/main/README.md) for API details. All public C functions and Macros have Odin binding equivalents, generally of the form `CLAY_ID` (C) -> `clay.ID` (Odin).
|
||||
|
@ -1,13 +1,13 @@
|
||||
cp ../../clay.h clay.c;
|
||||
# Intel Mac
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay.o -ffreestanding -static -target x86_64-apple-darwin clay.c -fPIC && ar r clay-odin/macos/clay.a clay.o;
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay.o -ffreestanding -static -target x86_64-apple-darwin clay.c -fPIC -O3 && ar r clay-odin/macos/clay.a clay.o;
|
||||
# ARM Mac
|
||||
clang -c -DCLAY_IMPLEMENTATION -g -o clay.o -static clay.c -fPIC && ar r clay-odin/macos-arm64/clay.a clay.o;
|
||||
clang -c -DCLAY_IMPLEMENTATION -g -o clay.o -static clay.c -fPIC -O3 && ar r clay-odin/macos-arm64/clay.a clay.o;
|
||||
# x64 Windows
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/windows/clay.lib -ffreestanding -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static clay.c;
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/windows/clay.lib -ffreestanding -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static -O3 clay.c;
|
||||
# Linux
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay.o -ffreestanding -static -target x86_64-unknown-linux-gnu clay.c -fPIC && ar r clay-odin/linux/clay.a clay.o;
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay.o -ffreestanding -static -target x86_64-unknown-linux-gnu clay.c -fPIC -O3 && ar r clay-odin/linux/clay.a clay.o;
|
||||
# WASM
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/wasm/clay.o -target wasm32 -nostdlib -static clay.c;
|
||||
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/wasm/clay.o -target wasm32 -nostdlib -static -O3 clay.c;
|
||||
rm clay.o;
|
||||
rm clay.c;
|
||||
|
@ -36,7 +36,7 @@ Dimensions :: struct {
|
||||
|
||||
Arena :: struct {
|
||||
nextAllocation: uintptr,
|
||||
capacity: uintptr,
|
||||
capacity: c.size_t,
|
||||
memory: [^]c.char,
|
||||
}
|
||||
|
||||
@ -367,7 +367,7 @@ Context :: struct {} // opaque structure, only use as a pointer
|
||||
@(link_prefix = "Clay_", default_calling_convention = "c")
|
||||
foreign Clay {
|
||||
MinMemorySize :: proc() -> u32 ---
|
||||
CreateArenaWithCapacityAndMemory :: proc(capacity: u32, offset: [^]u8) -> Arena ---
|
||||
CreateArenaWithCapacityAndMemory :: proc(capacity: c.size_t, offset: [^]u8) -> Arena ---
|
||||
SetPointerState :: proc(position: Vector2, pointerDown: bool) ---
|
||||
Initialize :: proc(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) -> ^Context ---
|
||||
GetCurrentContext :: proc() -> ^Context ---
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
244
clay.h
244
clay.h
@ -42,6 +42,12 @@
|
||||
#define CLAY_WASM_EXPORT(null)
|
||||
#endif
|
||||
|
||||
#ifdef CLAY_DLL
|
||||
#define CLAY_DLL_EXPORT __declspec(dllexport) __stdcall
|
||||
#else
|
||||
#define CLAY_DLL_EXPORT
|
||||
#endif
|
||||
|
||||
// Public Macro API ------------------------
|
||||
|
||||
#define CLAY__MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
@ -65,13 +71,25 @@
|
||||
|
||||
#define CLAY_SIZING_PERCENT(percentOfParent) (CLAY__INIT(Clay_SizingAxis) { .size = { .percent = (percentOfParent) }, .type = CLAY__SIZING_TYPE_PERCENT })
|
||||
|
||||
// Note: If a compile error led you here, you might be trying to use CLAY_ID with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID instead.
|
||||
#define CLAY_ID(label) CLAY_IDI(label, 0)
|
||||
|
||||
#define CLAY_IDI(label, index) Clay__HashString(CLAY_STRING(label), index, 0)
|
||||
#define CLAY_SID(label) CLAY_SIDI(label, 0)
|
||||
|
||||
// Note: If a compile error led you here, you might be trying to use CLAY_IDI with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI instead.
|
||||
#define CLAY_IDI(label, index) CLAY_SIDI(CLAY_STRING(label), index)
|
||||
|
||||
#define CLAY_SIDI(label, index) Clay__HashString(label, index, 0)
|
||||
|
||||
// Note: If a compile error led you here, you might be trying to use CLAY_ID_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SID_LOCAL instead.
|
||||
#define CLAY_ID_LOCAL(label) CLAY_IDI_LOCAL(label, 0)
|
||||
|
||||
#define CLAY_IDI_LOCAL(label, index) Clay__HashString(CLAY_STRING(label), index, Clay__GetParentElementId())
|
||||
#define CLAY_SID_LOCAL(label) CLAY_SIDI_LOCAL(label, 0)
|
||||
|
||||
// Note: If a compile error led you here, you might be trying to use CLAY_IDI_LOCAL with something other than a string literal. To construct an ID with a dynamic string, use CLAY_SIDI_LOCAL instead.
|
||||
#define CLAY_IDI_LOCAL(label, index) CLAY_SIDI_LOCAL(CLAY_STRING(label), index)
|
||||
|
||||
#define CLAY_SIDI_LOCAL(label, index) Clay__HashString(label, index, Clay__GetParentElementId())
|
||||
|
||||
#define CLAY__STRING_LENGTH(s) ((sizeof(s) / sizeof((s)[0])) - sizeof((s)[0]))
|
||||
|
||||
@ -248,7 +266,7 @@ typedef CLAY_PACKED_ENUM {
|
||||
CLAY_ALIGN_Y_TOP,
|
||||
// Aligns child elements to the bottom of this element, offset by padding.width.bottom
|
||||
CLAY_ALIGN_Y_BOTTOM,
|
||||
// Aligns child elements vertiically to the center of this element
|
||||
// Aligns child elements vertically to the center of this element
|
||||
CLAY_ALIGN_Y_CENTER,
|
||||
} Clay_LayoutAlignmentY;
|
||||
|
||||
@ -771,102 +789,102 @@ typedef struct {
|
||||
// Public API functions ------------------------------------------
|
||||
|
||||
// Returns the size, in bytes, of the minimum amount of memory Clay requires to operate at its current settings.
|
||||
uint32_t Clay_MinMemorySize(void);
|
||||
CLAY_DLL_EXPORT uint32_t Clay_MinMemorySize(void);
|
||||
// Creates an arena for clay to use for its internal allocations, given a certain capacity in bytes and a pointer to an allocation of at least that size.
|
||||
// Intended to be used with Clay_MinMemorySize in the following way:
|
||||
// uint32_t minMemoryRequired = Clay_MinMemorySize();
|
||||
// Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(minMemoryRequired, malloc(minMemoryRequired));
|
||||
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *memory);
|
||||
CLAY_DLL_EXPORT Clay_Arena Clay_CreateArenaWithCapacityAndMemory(size_t capacity, void *memory);
|
||||
// Sets the state of the "pointer" (i.e. the mouse or touch) in Clay's internal data. Used for detecting and responding to mouse events in the debug view,
|
||||
// as well as for Clay_Hovered() and scroll element handling.
|
||||
void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
|
||||
CLAY_DLL_EXPORT void Clay_SetPointerState(Clay_Vector2 position, bool pointerDown);
|
||||
// Initialize Clay's internal arena and setup required data before layout can begin. Only needs to be called once.
|
||||
// - arena can be created using Clay_CreateArenaWithCapacityAndMemory()
|
||||
// - layoutDimensions are the initial bounding dimensions of the layout (i.e. the screen width and height for a full screen layout)
|
||||
// - errorHandler is used by Clay to inform you if something has gone wrong in configuration or layout.
|
||||
Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
|
||||
CLAY_DLL_EXPORT Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler);
|
||||
// Returns the Context that clay is currently using. Used when using multiple instances of clay simultaneously.
|
||||
Clay_Context* Clay_GetCurrentContext(void);
|
||||
CLAY_DLL_EXPORT Clay_Context* Clay_GetCurrentContext(void);
|
||||
// Sets the context that clay will use to compute the layout.
|
||||
// Used to restore a context saved from Clay_GetCurrentContext when using multiple instances of clay simultaneously.
|
||||
void Clay_SetCurrentContext(Clay_Context* context);
|
||||
CLAY_DLL_EXPORT void Clay_SetCurrentContext(Clay_Context* context);
|
||||
// Updates the state of Clay's internal scroll data, updating scroll content positions if scrollDelta is non zero, and progressing momentum scrolling.
|
||||
// - enableDragScrolling when set to true will enable mobile device like "touch drag" scroll of scroll containers, including momentum scrolling after the touch has ended.
|
||||
// - scrollDelta is the amount to scroll this frame on each axis in pixels.
|
||||
// - deltaTime is the time in seconds since the last "frame" (scroll update)
|
||||
void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
|
||||
CLAY_DLL_EXPORT void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime);
|
||||
// Updates the layout dimensions in response to the window or outer container being resized.
|
||||
void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
|
||||
CLAY_DLL_EXPORT void Clay_SetLayoutDimensions(Clay_Dimensions dimensions);
|
||||
// Called before starting any layout declarations.
|
||||
void Clay_BeginLayout(void);
|
||||
CLAY_DLL_EXPORT void Clay_BeginLayout(void);
|
||||
// Called when all layout declarations are finished.
|
||||
// Computes the layout and generates and returns the array of render commands to draw.
|
||||
Clay_RenderCommandArray Clay_EndLayout(void);
|
||||
CLAY_DLL_EXPORT Clay_RenderCommandArray Clay_EndLayout(void);
|
||||
// Calculates a hash ID from the given idString.
|
||||
// Generally only used for dynamic strings when CLAY_ID("stringLiteral") can't be used.
|
||||
Clay_ElementId Clay_GetElementId(Clay_String idString);
|
||||
CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementId(Clay_String idString);
|
||||
// Calculates a hash ID from the given idString and index.
|
||||
// - index is used to avoid constructing dynamic ID strings in loops.
|
||||
// Generally only used for dynamic strings when CLAY_IDI("stringLiteral", index) can't be used.
|
||||
Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index);
|
||||
CLAY_DLL_EXPORT Clay_ElementId Clay_GetElementIdWithIndex(Clay_String idString, uint32_t index);
|
||||
// Returns layout data such as the final calculated bounding box for an element with a given ID.
|
||||
// The returned Clay_ElementData contains a `found` bool that will be true if an element with the provided ID was found.
|
||||
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
|
||||
Clay_ElementData Clay_GetElementData(Clay_ElementId id);
|
||||
CLAY_DLL_EXPORT Clay_ElementData Clay_GetElementData(Clay_ElementId id);
|
||||
// Returns true if the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
|
||||
// Works during element declaration, e.g. CLAY({ .backgroundColor = Clay_Hovered() ? BLUE : RED });
|
||||
bool Clay_Hovered(void);
|
||||
CLAY_DLL_EXPORT bool Clay_Hovered(void);
|
||||
// Bind a callback that will be called when the pointer position provided by Clay_SetPointerState is within the current element's bounding box.
|
||||
// - onHoverFunction is a function pointer to a user defined function.
|
||||
// - userData is a pointer that will be transparently passed through when the onHoverFunction is called.
|
||||
void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData);
|
||||
CLAY_DLL_EXPORT void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData);
|
||||
// An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
|
||||
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
|
||||
bool Clay_PointerOver(Clay_ElementId elementId);
|
||||
CLAY_DLL_EXPORT bool Clay_PointerOver(Clay_ElementId elementId);
|
||||
// Returns data representing the state of the scrolling element with the provided ID.
|
||||
// The returned Clay_ScrollContainerData contains a `found` bool that will be true if a scroll element was found with the provided ID.
|
||||
// An imperative function that returns true if the pointer position provided by Clay_SetPointerState is within the element with the provided ID's bounding box.
|
||||
// This ID can be calculated either with CLAY_ID() for string literal IDs, or Clay_GetElementId for dynamic strings.
|
||||
Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
|
||||
CLAY_DLL_EXPORT Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id);
|
||||
// Binds a callback function that Clay will call to determine the dimensions of a given string slice.
|
||||
// - measureTextFunction is a user provided function that adheres to the interface Clay_Dimensions (Clay_StringSlice text, Clay_TextElementConfig *config, void *userData);
|
||||
// - userData is a pointer that will be transparently passed through when the measureTextFunction is called.
|
||||
void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData);
|
||||
CLAY_DLL_EXPORT void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData), void *userData);
|
||||
// Experimental - Used in cases where Clay needs to integrate with a system that manages its own scrolling containers externally.
|
||||
// Please reach out if you plan to use this function, as it may be subject to change.
|
||||
void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData);
|
||||
CLAY_DLL_EXPORT void Clay_SetQueryScrollOffsetFunction(Clay_Vector2 (*queryScrollOffsetFunction)(uint32_t elementId, void *userData), void *userData);
|
||||
// A bounds-checked "get" function for the Clay_RenderCommandArray returned from Clay_EndLayout().
|
||||
Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
|
||||
CLAY_DLL_EXPORT Clay_RenderCommand * Clay_RenderCommandArray_Get(Clay_RenderCommandArray* array, int32_t index);
|
||||
// Enables and disables Clay's internal debug tools.
|
||||
// This state is retained and does not need to be set each frame.
|
||||
void Clay_SetDebugModeEnabled(bool enabled);
|
||||
CLAY_DLL_EXPORT void Clay_SetDebugModeEnabled(bool enabled);
|
||||
// Returns true if Clay's internal debug tools are currently enabled.
|
||||
bool Clay_IsDebugModeEnabled(void);
|
||||
CLAY_DLL_EXPORT bool Clay_IsDebugModeEnabled(void);
|
||||
// Enables and disables visibility culling. By default, Clay will not generate render commands for elements whose bounding box is entirely outside the screen.
|
||||
void Clay_SetCullingEnabled(bool enabled);
|
||||
CLAY_DLL_EXPORT void Clay_SetCullingEnabled(bool enabled);
|
||||
// Returns the maximum number of UI elements supported by Clay's current configuration.
|
||||
int32_t Clay_GetMaxElementCount(void);
|
||||
CLAY_DLL_EXPORT int32_t Clay_GetMaxElementCount(void);
|
||||
// Modifies the maximum number of UI elements supported by Clay's current configuration.
|
||||
// This may require reallocating additional memory, and re-calling Clay_Initialize();
|
||||
void Clay_SetMaxElementCount(int32_t maxElementCount);
|
||||
CLAY_DLL_EXPORT void Clay_SetMaxElementCount(int32_t maxElementCount);
|
||||
// Returns the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
|
||||
int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
|
||||
CLAY_DLL_EXPORT int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
|
||||
// Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
|
||||
// This may require reallocating additional memory, and re-calling Clay_Initialize();
|
||||
void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
|
||||
CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
|
||||
// Resets Clay's internal text measurement cache, useful if memory to represent strings is being re-used.
|
||||
// Similar behaviour can be achieved on an individual text element level by using Clay_TextElementConfig.hashStringContents
|
||||
void Clay_ResetMeasureTextCache(void);
|
||||
CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void);
|
||||
|
||||
// Internal API functions required by macros ----------------------
|
||||
|
||||
void Clay__OpenElement(void);
|
||||
void Clay__ConfigureOpenElement(const Clay_ElementDeclaration config);
|
||||
void Clay__CloseElement(void);
|
||||
Clay_ElementId Clay__HashString(Clay_String key, uint32_t offset, uint32_t seed);
|
||||
void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig);
|
||||
Clay_TextElementConfig *Clay__StoreTextElementConfig(Clay_TextElementConfig config);
|
||||
uint32_t Clay__GetParentElementId(void);
|
||||
CLAY_DLL_EXPORT void Clay__OpenElement(void);
|
||||
CLAY_DLL_EXPORT void Clay__ConfigureOpenElement(const Clay_ElementDeclaration config);
|
||||
CLAY_DLL_EXPORT void Clay__CloseElement(void);
|
||||
CLAY_DLL_EXPORT Clay_ElementId Clay__HashString(Clay_String key, uint32_t offset, uint32_t seed);
|
||||
CLAY_DLL_EXPORT void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig);
|
||||
CLAY_DLL_EXPORT Clay_TextElementConfig *Clay__StoreTextElementConfig(Clay_TextElementConfig config);
|
||||
CLAY_DLL_EXPORT uint32_t Clay__GetParentElementId(void);
|
||||
|
||||
extern Clay_Color Clay__debugViewHighlightColor;
|
||||
extern uint32_t Clay__debugViewWidth;
|
||||
@ -1445,7 +1463,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
||||
measured = Clay__MeasureTextCacheItemArray_Get(&context->measureTextHashMapInternal, newItemIndex);
|
||||
} else {
|
||||
if (context->measureTextHashMapInternal.length == context->measureTextHashMapInternal.capacity - 1) {
|
||||
if (context->booleanWarnings.maxTextMeasureCacheExceeded) {
|
||||
if (!context->booleanWarnings.maxTextMeasureCacheExceeded) {
|
||||
context->errorHandler.errorHandlerFunction(CLAY__INIT(Clay_ErrorData) {
|
||||
.errorType = CLAY_ERROR_TYPE_ELEMENTS_CAPACITY_EXCEEDED,
|
||||
.errorText = CLAY_STRING("Clay ran out of capacity while attempting to measure text elements. Try using Clay_SetMaxElementCount() with a higher value."),
|
||||
@ -2014,54 +2032,11 @@ void Clay__InitializePersistentMemory(Clay_Context* context) {
|
||||
context->arenaResetOffset = arena->nextAllocation;
|
||||
}
|
||||
|
||||
void Clay__CompressChildrenAlongAxis(bool xAxis, float totalSizeToDistribute, Clay__int32_tArray resizableContainerBuffer) {
|
||||
Clay_Context* context = Clay_GetCurrentContext();
|
||||
Clay__int32_tArray largestContainers = context->openClipElementStack;
|
||||
const float CLAY__EPSILON = 0.01;
|
||||
|
||||
while (totalSizeToDistribute > 0.1) {
|
||||
largestContainers.length = 0;
|
||||
float largestSize = 0;
|
||||
float targetSize = 0;
|
||||
for (int32_t i = 0; i < resizableContainerBuffer.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i));
|
||||
float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height;
|
||||
if ((childSize - largestSize) < 0.1 && (childSize - largestSize) > -0.1) {
|
||||
Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i));
|
||||
} else if (childSize > largestSize) {
|
||||
targetSize = largestSize;
|
||||
largestSize = childSize;
|
||||
largestContainers.length = 0;
|
||||
Clay__int32_tArray_Add(&largestContainers, Clay__int32_tArray_GetValue(&resizableContainerBuffer, i));
|
||||
}
|
||||
else if (childSize > targetSize) {
|
||||
targetSize = childSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (largestContainers.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
targetSize = CLAY__MAX(targetSize, (largestSize * largestContainers.length) - totalSizeToDistribute) / largestContainers.length;
|
||||
|
||||
for (int32_t childOffset = 0; childOffset < largestContainers.length; childOffset++) {
|
||||
int32_t childIndex = Clay__int32_tArray_GetValue(&largestContainers, childOffset);
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex);
|
||||
float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height;
|
||||
float childMinSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height;
|
||||
float oldChildSize = *childSize;
|
||||
*childSize = CLAY__MAX(childMinSize, targetSize);
|
||||
totalSizeToDistribute -= (oldChildSize - *childSize);
|
||||
if (*childSize == childMinSize) {
|
||||
for (int32_t i = 0; i < resizableContainerBuffer.length; i++) {
|
||||
if (Clay__int32_tArray_GetValue(&resizableContainerBuffer, i) == childIndex) {
|
||||
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bool Clay__FloatEqual(float left, float right) {
|
||||
float subtracted = left - right;
|
||||
return subtracted < CLAY__EPSILON && subtracted > -CLAY__EPSILON;
|
||||
}
|
||||
|
||||
void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
@ -2099,7 +2074,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
int32_t growContainerCount = 0;
|
||||
float parentSize = xAxis ? parent->dimensions.width : parent->dimensions.height;
|
||||
float parentPadding = (float)(xAxis ? (parent->layoutConfig->padding.left + parent->layoutConfig->padding.right) : (parent->layoutConfig->padding.top + parent->layoutConfig->padding.bottom));
|
||||
float innerContentSize = 0, growContainerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
|
||||
float innerContentSize = 0, totalPaddingAndChildGaps = parentPadding;
|
||||
bool sizingAlongAxis = (xAxis && parentStyleConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) || (!xAxis && parentStyleConfig->layoutDirection == CLAY_TOP_TO_BOTTOM);
|
||||
resizableContainerBuffer.length = 0;
|
||||
float parentChildGap = parentStyleConfig->childGap;
|
||||
@ -2125,7 +2100,6 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
if (sizingAlongAxis) {
|
||||
innerContentSize += (childSizing.type == CLAY__SIZING_TYPE_PERCENT ? 0 : childSize);
|
||||
if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
|
||||
growContainerContentSize += childSize;
|
||||
growContainerCount++;
|
||||
}
|
||||
if (childOffset > 0) {
|
||||
@ -2164,25 +2138,83 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
}
|
||||
}
|
||||
// Scrolling containers preferentially compress before others
|
||||
Clay__CompressChildrenAlongAxis(xAxis, -sizeToDistribute, resizableContainerBuffer);
|
||||
while (sizeToDistribute < -CLAY__EPSILON && resizableContainerBuffer.length > 0) {
|
||||
float largest = 0;
|
||||
float secondLargest = 0;
|
||||
float widthToAdd = sizeToDistribute;
|
||||
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
|
||||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
|
||||
float childSize = xAxis ? child->dimensions.width : child->dimensions.height;
|
||||
if (Clay__FloatEqual(childSize, largest)) { continue; }
|
||||
if (childSize > largest) {
|
||||
secondLargest = largest;
|
||||
largest = childSize;
|
||||
}
|
||||
if (childSize < largest) {
|
||||
secondLargest = CLAY__MAX(secondLargest, childSize);
|
||||
widthToAdd = secondLargest - largest;
|
||||
}
|
||||
}
|
||||
|
||||
widthToAdd = CLAY__MAX(widthToAdd, sizeToDistribute / resizableContainerBuffer.length);
|
||||
|
||||
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
|
||||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
|
||||
float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height;
|
||||
float minSize = xAxis ? child->minDimensions.width : child->minDimensions.height;
|
||||
float previousWidth = *childSize;
|
||||
if (Clay__FloatEqual(*childSize, largest)) {
|
||||
*childSize += widthToAdd;
|
||||
if (*childSize <= minSize) {
|
||||
*childSize = minSize;
|
||||
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
|
||||
}
|
||||
sizeToDistribute -= (*childSize - previousWidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
// The content is too small, allow SIZING_GROW containers to expand
|
||||
} else if (sizeToDistribute > 0 && growContainerCount > 0) {
|
||||
float targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount;
|
||||
for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset));
|
||||
Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height;
|
||||
if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
|
||||
float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height;
|
||||
float *minSize = xAxis ? &childElement->minDimensions.width : &childElement->minDimensions.height;
|
||||
if (targetSize < *minSize) {
|
||||
growContainerContentSize -= *minSize;
|
||||
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childOffset);
|
||||
growContainerCount--;
|
||||
targetSize = (sizeToDistribute + growContainerContentSize) / (float)growContainerCount;
|
||||
childOffset = -1;
|
||||
continue;
|
||||
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
|
||||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
|
||||
Clay__SizingType childSizing = xAxis ? child->layoutConfig->sizing.width.type : child->layoutConfig->sizing.height.type;
|
||||
if (childSizing != CLAY__SIZING_TYPE_GROW) {
|
||||
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
|
||||
}
|
||||
}
|
||||
while (sizeToDistribute > CLAY__EPSILON && resizableContainerBuffer.length > 0) {
|
||||
float smallest = CLAY__MAXFLOAT;
|
||||
float secondSmallest = CLAY__MAXFLOAT;
|
||||
float widthToAdd = sizeToDistribute;
|
||||
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
|
||||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
|
||||
float childSize = xAxis ? child->dimensions.width : child->dimensions.height;
|
||||
if (Clay__FloatEqual(childSize, smallest)) { continue; }
|
||||
if (childSize < smallest) {
|
||||
secondSmallest = smallest;
|
||||
smallest = childSize;
|
||||
}
|
||||
if (childSize > smallest) {
|
||||
secondSmallest = CLAY__MIN(secondSmallest, childSize);
|
||||
widthToAdd = secondSmallest - smallest;
|
||||
}
|
||||
}
|
||||
|
||||
widthToAdd = CLAY__MIN(widthToAdd, sizeToDistribute / resizableContainerBuffer.length);
|
||||
|
||||
for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) {
|
||||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex));
|
||||
float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height;
|
||||
float maxSize = xAxis ? child->layoutConfig->sizing.width.size.minMax.max : child->layoutConfig->sizing.height.size.minMax.max;
|
||||
float previousWidth = *childSize;
|
||||
if (Clay__FloatEqual(*childSize, smallest)) {
|
||||
*childSize += widthToAdd;
|
||||
if (*childSize >= maxSize) {
|
||||
*childSize = maxSize;
|
||||
Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--);
|
||||
}
|
||||
sizeToDistribute -= (*childSize - previousWidth);
|
||||
}
|
||||
*childSize = targetSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3591,7 +3623,7 @@ uint32_t Clay_MinMemorySize(void) {
|
||||
Clay_Context* currentContext = Clay_GetCurrentContext();
|
||||
if (currentContext) {
|
||||
fakeContext.maxElementCount = currentContext->maxElementCount;
|
||||
fakeContext.maxMeasureTextCacheWordCount = currentContext->maxElementCount;
|
||||
fakeContext.maxMeasureTextCacheWordCount = currentContext->maxMeasureTextCacheWordCount;
|
||||
}
|
||||
// Reserve space in the arena for the context, important for calculating min memory size correctly
|
||||
Clay__Context_Allocate_Arena(&fakeContext.internalArena);
|
||||
@ -3601,7 +3633,7 @@ uint32_t Clay_MinMemorySize(void) {
|
||||
}
|
||||
|
||||
CLAY_WASM_EXPORT("Clay_CreateArenaWithCapacityAndMemory")
|
||||
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *memory) {
|
||||
Clay_Arena Clay_CreateArenaWithCapacityAndMemory(size_t capacity, void *memory) {
|
||||
Clay_Arena arena = {
|
||||
.capacity = capacity,
|
||||
.memory = (char *)memory
|
||||
|
Binary file not shown.
@ -91,8 +91,11 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_Tex
|
||||
float textHeight = config->fontSize;
|
||||
Font* fonts = (Font*)userData;
|
||||
Font fontToUse = fonts[config->fontId];
|
||||
// Font failed to load, likely the fonts are in the wrong place relative to the execution dir
|
||||
if (!fontToUse.glyphs) return textSize;
|
||||
// Font failed to load, likely the fonts are in the wrong place relative to the execution dir.
|
||||
// RayLib ships with a default font, so we can continue with that built in one.
|
||||
if (!fontToUse.glyphs) {
|
||||
fontToUse = GetFontDefault();
|
||||
}
|
||||
|
||||
float scaleFactor = config->fontSize/(float)fontToUse.baseSize;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user