mirror of
				https://github.com/nicbarker/clay.git
				synced 2025-11-04 00:26:17 +00:00 
			
		
		
		
	[Documentation] Update README.md for Odin bindings to reflect the latest API changes. (#281)
				
					
				
			This commit is contained in:
		
							parent
							
								
									766325c395
								
							
						
					
					
						commit
						feead45f3e
					
				| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
### Odin Language Bindings
 | 
					### 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
 | 
					Special thanks to
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,20 +8,20 @@ Special thanks to
 | 
				
			||||||
- [Dudejoe870](https://github.com/Dudejoe870)
 | 
					- [Dudejoe870](https://github.com/Dudejoe870)
 | 
				
			||||||
- MrStevns from the Odin Discord server
 | 
					- 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.
 | 
					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):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
// C form of element macros
 | 
					// 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), {
 | 
					// Define an element with 16px of x and y padding
 | 
				
			||||||
 | 
					CLAY({ .id = CLAY_ID("Outer"), .layout = { .padding = CLAY_PADDING_ALL(16) } }) {
 | 
				
			||||||
  // Child elements here
 | 
					  // Child elements here
 | 
				
			||||||
});
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```Odin
 | 
					```Odin
 | 
				
			||||||
// Odin form of element macros
 | 
					// 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 })) {
 | 
					if clay.UI()({ id = clay.ID("Outer"), layout = { padding = clay.PaddingAll(16) }}) {
 | 
				
			||||||
    // Child elements here
 | 
					    // Child elements here
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
| 
						 | 
					@ -34,111 +34,170 @@ if clay.Rectangle(clay.ID("SideBar"), clay.Layout({ layoutDirection = .TOP_TO_BO
 | 
				
			||||||
import clay "clay-odin"
 | 
					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
 | 
					```Odin
 | 
				
			||||||
minMemorySize: u32 = clay.MinMemorySize()
 | 
					error_handler :: proc "c" (errorData: clay.ErrorData) {
 | 
				
			||||||
memory := make([^]u8, minMemorySize)
 | 
					    // Do something with the error data.
 | 
				
			||||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
 | 
					}
 | 
				
			||||||
clay.Initialize(arena)
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					```Odin
 | 
				
			||||||
// Example measure text function
 | 
					// Example measure text function
 | 
				
			||||||
measureText :: proc "c" (text: ^clay.String, config: ^clay.TextElementConfig) -> clay.Dimensions {
 | 
					measure_text :: proc "c" (
 | 
				
			||||||
    // clay.TextElementConfig contains members such as fontId, fontSize, letterSpacing etc
 | 
					    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
 | 
					    // 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
 | 
					// Tell clay how to measure text
 | 
				
			||||||
clay.SetMeasureTextFunction(measureText)
 | 
					clay.SetMeasureTextFunction(measure_text, nil)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. **Optional** - Call [clay.SetPointerPosition(pointerPosition)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setpointerposition) if you want to use mouse interactions.
 | 
					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
 | 
					```Odin
 | 
				
			||||||
// Update internal pointer position for handling mouseover / click / touch events
 | 
					// 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
 | 
					```Odin
 | 
				
			||||||
 | 
					// Define some colors.
 | 
				
			||||||
COLOR_LIGHT :: clay.Color{224, 215, 210, 255}
 | 
					COLOR_LIGHT :: clay.Color{224, 215, 210, 255}
 | 
				
			||||||
COLOR_RED :: clay.Color{168, 66, 28, 255}
 | 
					COLOR_RED :: clay.Color{168, 66, 28, 255}
 | 
				
			||||||
COLOR_ORANGE :: clay.Color{225, 138, 50, 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
 | 
					// Layout config is just a struct that can be declared statically, or inline
 | 
				
			||||||
sidebarItemLayout := clay.LayoutConfig {
 | 
					sidebar_item_layout := clay.LayoutConfig {
 | 
				
			||||||
    sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(50)},
 | 
					    sizing = {
 | 
				
			||||||
 | 
					        width = clay.SizingGrow({}),
 | 
				
			||||||
 | 
					        height = clay.SizingFixed(50)
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Re-useable components are just normal functions
 | 
					// Re-useable components are just normal procs.
 | 
				
			||||||
SidebarItemComponent :: proc(index: u32) {
 | 
					sidebar_item_component :: proc(index: u32) {
 | 
				
			||||||
    if clay.Rectangle(clay.ID("SidebarBlob", index), &sidebarItemLayout, clay.RectangleConfig({color = COLOR_ORANGE})) {}
 | 
					    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
 | 
					// An example function to create your layout tree
 | 
				
			||||||
CreateLayout :: proc() -> clay.ClayArray(clay.RenderCommand) {
 | 
					create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
 | 
				
			||||||
    clay.BeginLayout(windowWidth, windowHeight)
 | 
					    // Begin constructing the layout.
 | 
				
			||||||
 | 
					    clay.BeginLayout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // An example of laying out a UI with a fixed width sidebar and flexible width main content
 | 
					    // 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
 | 
					    // NOTE: To create a scope for child components, the Odin API uses `if` with components that have children
 | 
				
			||||||
    if clay.Rectangle(
 | 
					    if clay.UI()({
 | 
				
			||||||
        clay.ID("OuterContainer"),
 | 
					        id = clay.ID("OuterContainer"),
 | 
				
			||||||
        clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
 | 
					        layout = {
 | 
				
			||||||
        clay.RectangleConfig({color = {250, 250, 255, 255}}),
 | 
					            sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
 | 
				
			||||||
    ) {
 | 
					            padding = { 16, 16, 16, 16 },
 | 
				
			||||||
        if clay.Rectangle(
 | 
					            childGap = 16,
 | 
				
			||||||
            clay.ID("SideBar"),
 | 
					        },
 | 
				
			||||||
            clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = clay.SizingFixed(300), height = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16}),
 | 
					        backgroundColor = { 250, 250, 255, 255 },
 | 
				
			||||||
            clay.RectangleConfig({color = COLOR_LIGHT}),
 | 
					    }) {
 | 
				
			||||||
        ) {
 | 
					        if clay.UI()({
 | 
				
			||||||
            if clay.Rectangle(
 | 
					            id = clay.ID("SideBar"),
 | 
				
			||||||
                clay.ID("ProfilePictureOuter"),
 | 
					            layout = {
 | 
				
			||||||
                clay.Layout({sizing = {width = clay.SizingGrow({})}, padding = {16, 16}, childGap = 16, childAlignment = {y = .CENTER}}),
 | 
					                layoutDirection = .TopToBottom,
 | 
				
			||||||
                clay.RectangleConfig({color = COLOR_RED}),
 | 
					                sizing = { width = clay.SizingFixed(300), height = clay.SizingGrow({}) },
 | 
				
			||||||
            ) {
 | 
					                padding = { 16, 16, 16, 16 },
 | 
				
			||||||
                if clay.Image(
 | 
					                childGap = 16,
 | 
				
			||||||
                    clay.ID("ProfilePicture"),
 | 
					            },
 | 
				
			||||||
                    clay.Layout({sizing = {width = clay.SizingFixed(60), height = clay.SizingFixed(60)}}),
 | 
					            backgroundColor = COLOR_LIGHT,
 | 
				
			||||||
                    clay.ImageConfig({imageData = &profilePicture, sourceDimensions = {height = 60, width = 60}}),
 | 
					        }) {
 | 
				
			||||||
                ) {}
 | 
					            if clay.UI()({
 | 
				
			||||||
                clay.Text(clay.ID("ProfileTitle"), "Clay - UI Library", clay.TextConfig({fontSize = 24, textColor = {255, 255, 255, 255}}))
 | 
					                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
 | 
					            // Standard Odin code like loops, etc. work inside components.
 | 
				
			||||||
            for i in 0..<10 {
 | 
					            // Here we render 5 sidebar items.
 | 
				
			||||||
                SidebarItemComponent(i)
 | 
					            for i in u32(0)..<5 {
 | 
				
			||||||
 | 
					                sidebar_item_component(i)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if clay.Rectangle(
 | 
					        if clay.UI()({
 | 
				
			||||||
            clay.ID("MainContent"),
 | 
					            id = clay.ID("MainContent"),
 | 
				
			||||||
            clay.Layout({sizing = {width = clay.SizingGrow({}), height = clay.SizingGrow({})}}),
 | 
					            layout = {
 | 
				
			||||||
            clay.RectangleConfig({color = COLOR_LIGHT}),
 | 
					                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
 | 
					```Odin
 | 
				
			||||||
renderCommands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout(windowWidth, windowHeight)
 | 
					render_commands := create_layout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
for i: u32 = 0; i < renderCommands.length; i += 1 {
 | 
					for i in 0..<i32(render_commands.length) {
 | 
				
			||||||
    renderCommand := clay.RenderCommandArray_Get(&renderCommands, cast(i32)i)
 | 
					    render_command := clay.RenderCommandArray_Get(render_commands, i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    switch renderCommand.commandType {
 | 
					    switch render_command.commandType {
 | 
				
			||||||
    case .Rectangle:
 | 
					    case .Rectangle:
 | 
				
			||||||
        DrawRectangle(renderCommand.boundingBox, renderCommand.config.rectangleElementConfig.color)
 | 
					        DrawRectangle(render_command.boundingBox, render_command.config.rectangleElementConfig.color)
 | 
				
			||||||
    // ... Implement handling of other command types
 | 
					    // ... 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).
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue