lil ui
This commit is contained in:
parent
ded8dbba8c
commit
85840db0f1
13 changed files with 6010 additions and 7 deletions
22
libraries/clay/LICENSE.md
Normal file
22
libraries/clay/LICENSE.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
zlib/libpng license
|
||||||
|
|
||||||
|
Copyright (c) 2024 Nic Barker
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied warranty.
|
||||||
|
In no event will the authors be held liable for any damages arising from the
|
||||||
|
use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software in a
|
||||||
|
product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not
|
||||||
|
be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
203
libraries/clay/README.md
Normal file
203
libraries/clay/README.md
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
### 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.
|
||||||
|
|
||||||
|
Special thanks to
|
||||||
|
|
||||||
|
- [laytan](https://github.com/laytan)
|
||||||
|
- [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):
|
||||||
|
```C
|
||||||
|
// C form of element macros
|
||||||
|
// 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.UI(clay.ID("Outer"))({ layout = { padding = clay.PaddingAll(16) }}) {
|
||||||
|
// Child elements here
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
1. Download the [clay-odin](https://github.com/nicbarker/clay/tree/main/bindings/odin/clay-odin) directory and copy it into your project.
|
||||||
|
|
||||||
|
```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(clay.Arena, clay.Dimensions, clay.ErrorHandler)](https://github.com/nicbarker/clay/blob/main/README.md#clay_initialize).
|
||||||
|
|
||||||
|
```Odin
|
||||||
|
error_handler :: proc "c" (errorData: clay.ErrorData) {
|
||||||
|
// Do something with the error data.
|
||||||
|
}
|
||||||
|
|
||||||
|
min_memory_size := clay.MinMemorySize()
|
||||||
|
memory := make([^]u8, min_memory_size)
|
||||||
|
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(uint(min_memory_size), memory)
|
||||||
|
clay.Initialize(arena, {1080, 720}, { handler = error_handler })
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
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(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.SetPointerState(
|
||||||
|
{ mouse_pos_x, mouse_pos_y },
|
||||||
|
is_mouse_down,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
sidebar_item_layout := clay.LayoutConfig {
|
||||||
|
sizing = {
|
||||||
|
width = clay.SizingGrow({}),
|
||||||
|
height = clay.SizingFixed(50)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 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.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 = {
|
||||||
|
// How you define `profile_picture` depends on your renderer.
|
||||||
|
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.
|
||||||
|
// Here we render 5 sidebar items.
|
||||||
|
for i in u32(0)..<5 {
|
||||||
|
sidebar_item_component(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if clay.UI()({
|
||||||
|
id = clay.ID("MainContent"),
|
||||||
|
layout = {
|
||||||
|
sizing = { width = clay.SizingGrow({}), height = clay.SizingGrow({}) },
|
||||||
|
},
|
||||||
|
backgroundColor = COLOR_LIGHT,
|
||||||
|
}) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns a list of render commands
|
||||||
|
return clay.EndLayout()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
render_commands := create_layout()
|
||||||
|
|
||||||
|
for i in 0..<i32(render_commands.length) {
|
||||||
|
render_command := clay.RenderCommandArray_Get(render_commands, i)
|
||||||
|
|
||||||
|
switch render_command.commandType {
|
||||||
|
case .Rectangle:
|
||||||
|
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_ID` (C) -> `clay.ID` (Odin).
|
||||||
19
libraries/clay/build-clay-lib.sh
Executable file
19
libraries/clay/build-clay-lib.sh
Executable file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Intel Mac
|
||||||
|
rm -f clay-odin/macos/clay.a
|
||||||
|
clang -c -o clay.o -ffreestanding -static -target x86_64-apple-darwin clay-odin/clay.c -fPIC -O3
|
||||||
|
ar r clay-odin/macos/clay.a clay.o;
|
||||||
|
# ARM Mac
|
||||||
|
rm -f clay-odin/macos-arm64/clay.a
|
||||||
|
clang -c -g -o clay.o -static clay-odin/clay.c -fPIC -O3
|
||||||
|
ar r clay-odin/macos-arm64/clay.a clay.o;
|
||||||
|
# x64 Windows
|
||||||
|
rm -f clay-odin/windows/clay.lib
|
||||||
|
clang -c -o clay-odin/windows/clay.lib -ffreestanding -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static -O3 clay-odin/clay.c;
|
||||||
|
# Linux
|
||||||
|
rm -f clay-odin/linux/clay.a
|
||||||
|
clang -c -o clay.o -ffreestanding -static -target x86_64-unknown-linux-gnu clay-odin/clay.c -fPIC -O3
|
||||||
|
ar r clay-odin/linux/clay.a clay.o;
|
||||||
|
# WASM
|
||||||
|
rm -f clay-odin/wasm/clay.o
|
||||||
|
clang -c -o clay-odin/wasm/clay.o -target wasm32 -nostdlib -static -O3 clay-odin/clay.c;
|
||||||
|
rm clay.o;
|
||||||
2
libraries/clay/clay-odin/clay.c
Normal file
2
libraries/clay/clay-odin/clay.c
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#define CLAY_IMPLEMENTATION
|
||||||
|
#include "clay.h"
|
||||||
5058
libraries/clay/clay-odin/clay.h
Normal file
5058
libraries/clay/clay-odin/clay.h
Normal file
File diff suppressed because it is too large
Load diff
BIN
libraries/clay/clay-odin/linux/clay.a
Normal file
BIN
libraries/clay/clay-odin/linux/clay.a
Normal file
Binary file not shown.
BIN
libraries/clay/clay-odin/macos-arm64/clay.a
Normal file
BIN
libraries/clay/clay-odin/macos-arm64/clay.a
Normal file
Binary file not shown.
BIN
libraries/clay/clay-odin/macos/clay.a
Normal file
BIN
libraries/clay/clay-odin/macos/clay.a
Normal file
Binary file not shown.
BIN
libraries/clay/clay-odin/wasm/clay.o
Normal file
BIN
libraries/clay/clay-odin/wasm/clay.o
Normal file
Binary file not shown.
BIN
libraries/clay/clay-odin/windows/clay.lib
Normal file
BIN
libraries/clay/clay-odin/windows/clay.lib
Normal file
Binary file not shown.
601
libraries/clay/clay.odin
Normal file
601
libraries/clay/clay.odin
Normal file
|
|
@ -0,0 +1,601 @@
|
||||||
|
package clay
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
|
foreign import Clay "clay-odin/windows/clay.lib"
|
||||||
|
} else when ODIN_OS == .Linux {
|
||||||
|
foreign import Clay "clay-odin/linux/clay.a"
|
||||||
|
} else when ODIN_OS == .Darwin {
|
||||||
|
when ODIN_ARCH == .arm64 {
|
||||||
|
foreign import Clay "clay-odin/macos-arm64/clay.a"
|
||||||
|
} else {
|
||||||
|
foreign import Clay "clay-odin/macos/clay.a"
|
||||||
|
}
|
||||||
|
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||||
|
foreign import Clay "clay-odin/wasm/clay.o"
|
||||||
|
}
|
||||||
|
|
||||||
|
String :: struct {
|
||||||
|
isStaticallyAllocated: c.bool,
|
||||||
|
length: c.int32_t,
|
||||||
|
chars: [^]c.char,
|
||||||
|
}
|
||||||
|
|
||||||
|
StringSlice :: struct {
|
||||||
|
length: c.int32_t,
|
||||||
|
chars: [^]c.char,
|
||||||
|
baseChars: [^]c.char,
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector2 :: [2]c.float
|
||||||
|
|
||||||
|
Dimensions :: struct {
|
||||||
|
width: c.float,
|
||||||
|
height: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
Arena :: struct {
|
||||||
|
nextAllocation: uintptr,
|
||||||
|
capacity: c.size_t,
|
||||||
|
memory: [^]c.char,
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox :: struct {
|
||||||
|
x: c.float,
|
||||||
|
y: c.float,
|
||||||
|
width: c.float,
|
||||||
|
height: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
Color :: [4]c.float
|
||||||
|
|
||||||
|
CornerRadius :: struct {
|
||||||
|
topLeft: c.float,
|
||||||
|
topRight: c.float,
|
||||||
|
bottomLeft: c.float,
|
||||||
|
bottomRight: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementId :: struct {
|
||||||
|
id: u32,
|
||||||
|
offset: u32,
|
||||||
|
baseId: u32,
|
||||||
|
stringId: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementIdArray :: struct {
|
||||||
|
capacity: i32,
|
||||||
|
length: i32,
|
||||||
|
internalArray: [^]ElementId,
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
|
EnumBackingType :: u32
|
||||||
|
} else {
|
||||||
|
EnumBackingType :: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderCommandType :: enum EnumBackingType {
|
||||||
|
None,
|
||||||
|
Rectangle,
|
||||||
|
Border,
|
||||||
|
Text,
|
||||||
|
Image,
|
||||||
|
ScissorStart,
|
||||||
|
ScissorEnd,
|
||||||
|
OverlayColorStart,
|
||||||
|
OverlayColorEnd,
|
||||||
|
Custom,
|
||||||
|
}
|
||||||
|
|
||||||
|
RectangleElementConfig :: struct {
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
TextWrapMode :: enum EnumBackingType {
|
||||||
|
Words,
|
||||||
|
Newlines,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
TextAlignment :: enum EnumBackingType {
|
||||||
|
Left,
|
||||||
|
Center,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
TextElementConfig :: struct {
|
||||||
|
userData: rawptr,
|
||||||
|
textColor: Color,
|
||||||
|
fontId: u16,
|
||||||
|
fontSize: u16,
|
||||||
|
letterSpacing: u16,
|
||||||
|
lineHeight: u16,
|
||||||
|
wrapMode: TextWrapMode,
|
||||||
|
textAlignment: TextAlignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
AspectRatioElementConfig :: struct {
|
||||||
|
aspectRatio: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageElementConfig :: struct {
|
||||||
|
imageData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomElementConfig :: struct {
|
||||||
|
customData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderWidth :: struct {
|
||||||
|
left: u16,
|
||||||
|
right: u16,
|
||||||
|
top: u16,
|
||||||
|
bottom: u16,
|
||||||
|
betweenChildren: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderElementConfig :: struct {
|
||||||
|
color: Color,
|
||||||
|
width: BorderWidth,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionData :: struct {
|
||||||
|
boundingBox: BoundingBox,
|
||||||
|
backgroundColor: Color,
|
||||||
|
overlayColor: Color,
|
||||||
|
borderColor: Color,
|
||||||
|
borderWidth: BorderWidth,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionState :: enum c.int {
|
||||||
|
Idle,
|
||||||
|
Entering,
|
||||||
|
Transitioning,
|
||||||
|
Exiting,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionProperty :: enum c.int {
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Width,
|
||||||
|
Height,
|
||||||
|
BackgroundColor,
|
||||||
|
OverlayColor,
|
||||||
|
CornerRadius,
|
||||||
|
BorderColor,
|
||||||
|
BorderWidth,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionPropertyFlags :: bit_set[TransitionProperty;c.int]
|
||||||
|
TransitionPropertyPosition :: TransitionPropertyFlags{.X, .Y}
|
||||||
|
TransitionPropertyDimensions :: TransitionPropertyFlags{.Width, .Height}
|
||||||
|
TransitionPropertyBoundingBox :: TransitionPropertyPosition + TransitionPropertyDimensions
|
||||||
|
TransitionPropertyBorder :: TransitionPropertyFlags{.BorderColor, .BorderWidth}
|
||||||
|
|
||||||
|
TransitionCallbackArguments :: struct {
|
||||||
|
transitionState: TransitionState,
|
||||||
|
initial: TransitionData,
|
||||||
|
current: ^TransitionData,
|
||||||
|
target: TransitionData,
|
||||||
|
elapsedTime: f32,
|
||||||
|
duration: f32,
|
||||||
|
properties: TransitionPropertyFlags,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEnterTriggerType :: enum EnumBackingType {
|
||||||
|
SkipOnFirstParentFrame,
|
||||||
|
TriggerOnFirstParentFrame,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionExitTriggerType :: enum EnumBackingType {
|
||||||
|
SkipWhenParentExits,
|
||||||
|
TriggerWhenParentExits,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionInteractionHandlingType :: enum EnumBackingType {
|
||||||
|
DisableInteractionsWhileTransitioningPosition,
|
||||||
|
AllowInteractionsWhileTransitioningPosition,
|
||||||
|
}
|
||||||
|
|
||||||
|
ExitTransitionSiblingOrdering :: enum EnumBackingType {
|
||||||
|
UnderneathSiblings,
|
||||||
|
NaturalOrder,
|
||||||
|
AboveSiblings,
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionElementConfig :: struct {
|
||||||
|
handler: proc "c" (args: TransitionCallbackArguments) -> bool,
|
||||||
|
duration: f32,
|
||||||
|
properties: TransitionPropertyFlags,
|
||||||
|
interactionHandling: TransitionInteractionHandlingType,
|
||||||
|
enter: struct {
|
||||||
|
setInitialState: proc "c" (initialState: TransitionData, properties: TransitionPropertyFlags) -> TransitionData,
|
||||||
|
trigger: TransitionEnterTriggerType,
|
||||||
|
},
|
||||||
|
exit: struct {
|
||||||
|
setFinalState: proc "c" (finalState: TransitionData, properties: TransitionPropertyFlags) -> TransitionData,
|
||||||
|
trigger: TransitionExitTriggerType,
|
||||||
|
siblingOrdering: ExitTransitionSiblingOrdering,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipElementConfig :: struct {
|
||||||
|
horizontal: bool, // clip overflowing elements on the "X" axis
|
||||||
|
vertical: bool, // clip overflowing elements on the "Y" axis
|
||||||
|
childOffset: Vector2, // offsets the [X,Y] positions of all child elements, primarily for scrolling containers
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingAttachPointType :: enum EnumBackingType {
|
||||||
|
LeftTop,
|
||||||
|
LeftCenter,
|
||||||
|
LeftBottom,
|
||||||
|
CenterTop,
|
||||||
|
CenterCenter,
|
||||||
|
CenterBottom,
|
||||||
|
RightTop,
|
||||||
|
RightCenter,
|
||||||
|
RightBottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingAttachPoints :: struct {
|
||||||
|
element: FloatingAttachPointType,
|
||||||
|
parent: FloatingAttachPointType,
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerCaptureMode :: enum EnumBackingType {
|
||||||
|
Capture,
|
||||||
|
Passthrough,
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingAttachToElement :: enum EnumBackingType {
|
||||||
|
None,
|
||||||
|
Parent,
|
||||||
|
ElementWithId,
|
||||||
|
Root,
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingClipToElement :: enum EnumBackingType {
|
||||||
|
None,
|
||||||
|
AttachedParent,
|
||||||
|
}
|
||||||
|
|
||||||
|
FloatingElementConfig :: struct {
|
||||||
|
offset: Vector2,
|
||||||
|
expand: Dimensions,
|
||||||
|
parentId: u32,
|
||||||
|
zIndex: i16,
|
||||||
|
attachment: FloatingAttachPoints,
|
||||||
|
pointerCaptureMode: PointerCaptureMode,
|
||||||
|
attachTo: FloatingAttachToElement,
|
||||||
|
clipTo: FloatingClipToElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
TextRenderData :: struct {
|
||||||
|
stringContents: StringSlice,
|
||||||
|
textColor: Color,
|
||||||
|
fontId: u16,
|
||||||
|
fontSize: u16,
|
||||||
|
letterSpacing: u16,
|
||||||
|
lineHeight: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
RectangleRenderData :: struct {
|
||||||
|
backgroundColor: Color,
|
||||||
|
cornerRadius: CornerRadius,
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageRenderData :: struct {
|
||||||
|
backgroundColor: Color,
|
||||||
|
cornerRadius: CornerRadius,
|
||||||
|
imageData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomRenderData :: struct {
|
||||||
|
backgroundColor: Color,
|
||||||
|
cornerRadius: CornerRadius,
|
||||||
|
customData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipRenderData :: struct {
|
||||||
|
horizontal: bool,
|
||||||
|
vertical: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
OverlayColorRenderData :: struct {
|
||||||
|
color: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderRenderData :: struct {
|
||||||
|
color: Color,
|
||||||
|
cornerRadius: CornerRadius,
|
||||||
|
width: BorderWidth,
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderCommandData :: struct #raw_union {
|
||||||
|
rectangle: RectangleRenderData,
|
||||||
|
text: TextRenderData,
|
||||||
|
image: ImageRenderData,
|
||||||
|
custom: CustomRenderData,
|
||||||
|
border: BorderRenderData,
|
||||||
|
clip: ClipRenderData,
|
||||||
|
overlayColor: OverlayColorRenderData,
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderCommand :: struct {
|
||||||
|
boundingBox: BoundingBox,
|
||||||
|
renderData: RenderCommandData,
|
||||||
|
userData: rawptr,
|
||||||
|
id: u32,
|
||||||
|
zIndex: i16,
|
||||||
|
commandType: RenderCommandType,
|
||||||
|
}
|
||||||
|
|
||||||
|
ScrollContainerData :: struct {
|
||||||
|
// Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout.
|
||||||
|
// Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
|
||||||
|
scrollPosition: ^Vector2,
|
||||||
|
scrollContainerDimensions: Dimensions,
|
||||||
|
contentDimensions: Dimensions,
|
||||||
|
config: ClipElementConfig,
|
||||||
|
// Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
|
||||||
|
found: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementData :: struct {
|
||||||
|
boundingBox: BoundingBox,
|
||||||
|
found: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerDataInteractionState :: enum EnumBackingType {
|
||||||
|
PressedThisFrame,
|
||||||
|
Pressed,
|
||||||
|
ReleasedThisFrame,
|
||||||
|
Released,
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerData :: struct {
|
||||||
|
position: Vector2,
|
||||||
|
state: PointerDataInteractionState,
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingType :: enum EnumBackingType {
|
||||||
|
Fit,
|
||||||
|
Grow,
|
||||||
|
Percent,
|
||||||
|
Fixed,
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingConstraintsMinMax :: struct {
|
||||||
|
min: c.float,
|
||||||
|
max: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingConstraints :: struct #raw_union {
|
||||||
|
sizeMinMax: SizingConstraintsMinMax,
|
||||||
|
sizePercent: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingAxis :: struct {
|
||||||
|
// Note: `min` is used for CLAY_SIZING_PERCENT, slightly different to clay.h due to lack of C anonymous unions
|
||||||
|
constraints: SizingConstraints,
|
||||||
|
type: SizingType,
|
||||||
|
}
|
||||||
|
|
||||||
|
Sizing :: struct {
|
||||||
|
width: SizingAxis,
|
||||||
|
height: SizingAxis,
|
||||||
|
}
|
||||||
|
|
||||||
|
Padding :: struct {
|
||||||
|
left: u16,
|
||||||
|
right: u16,
|
||||||
|
top: u16,
|
||||||
|
bottom: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutDirection :: enum EnumBackingType {
|
||||||
|
LeftToRight,
|
||||||
|
TopToBottom,
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutAlignmentX :: enum EnumBackingType {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
Center,
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutAlignmentY :: enum EnumBackingType {
|
||||||
|
Top,
|
||||||
|
Bottom,
|
||||||
|
Center,
|
||||||
|
}
|
||||||
|
|
||||||
|
ChildAlignment :: struct {
|
||||||
|
x: LayoutAlignmentX,
|
||||||
|
y: LayoutAlignmentY,
|
||||||
|
}
|
||||||
|
|
||||||
|
LayoutConfig :: struct {
|
||||||
|
sizing: Sizing,
|
||||||
|
padding: Padding,
|
||||||
|
childGap: u16,
|
||||||
|
childAlignment: ChildAlignment,
|
||||||
|
layoutDirection: LayoutDirection,
|
||||||
|
}
|
||||||
|
|
||||||
|
ClayArray :: struct($type: typeid) {
|
||||||
|
capacity: i32,
|
||||||
|
length: i32,
|
||||||
|
internalArray: [^]type,
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementDeclaration :: struct {
|
||||||
|
layout: LayoutConfig,
|
||||||
|
backgroundColor: Color,
|
||||||
|
overlayColor: Color,
|
||||||
|
cornerRadius: CornerRadius,
|
||||||
|
aspectRatio: AspectRatioElementConfig,
|
||||||
|
image: ImageElementConfig,
|
||||||
|
floating: FloatingElementConfig,
|
||||||
|
custom: CustomElementConfig,
|
||||||
|
clip: ClipElementConfig,
|
||||||
|
border: BorderElementConfig,
|
||||||
|
transition: TransitionElementConfig,
|
||||||
|
userData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorType :: enum EnumBackingType {
|
||||||
|
TextMeasurementFunctionNotProvided,
|
||||||
|
ArenaCapacityExceeded,
|
||||||
|
ElementsCapacityExceeded,
|
||||||
|
TextMeasurementCapacityExceeded,
|
||||||
|
DuplicateId,
|
||||||
|
FloatingContainerParentNotFound,
|
||||||
|
PercentageOver1,
|
||||||
|
InternalError,
|
||||||
|
UnbalancedOpenClose,
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorData :: struct {
|
||||||
|
errorType: ErrorType,
|
||||||
|
errorText: String,
|
||||||
|
userData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorHandler :: struct {
|
||||||
|
handler: proc "c" (errorData: ErrorData),
|
||||||
|
userData: rawptr,
|
||||||
|
}
|
||||||
|
|
||||||
|
Context :: struct {} // opaque structure, only use as a pointer
|
||||||
|
|
||||||
|
@(link_prefix = "Clay_", default_calling_convention = "c")
|
||||||
|
foreign Clay {
|
||||||
|
_OpenElement :: proc() ---
|
||||||
|
_OpenElementWithId :: proc(id: ElementId) ---
|
||||||
|
_CloseElement :: proc() ---
|
||||||
|
MinMemorySize :: proc() -> u32 ---
|
||||||
|
CreateArenaWithCapacityAndMemory :: proc(capacity: c.size_t, offset: [^]u8) -> Arena ---
|
||||||
|
SetPointerState :: proc(position: Vector2, pointerDown: bool) ---
|
||||||
|
GetPointerState :: proc() -> PointerData ---
|
||||||
|
Initialize :: proc(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) -> ^Context ---
|
||||||
|
GetCurrentContext :: proc() -> ^Context ---
|
||||||
|
SetCurrentContext :: proc(ctx: ^Context) ---
|
||||||
|
UpdateScrollContainers :: proc(enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: c.float) ---
|
||||||
|
SetLayoutDimensions :: proc(dimensions: Dimensions) ---
|
||||||
|
BeginLayout :: proc() ---
|
||||||
|
EndLayout :: proc(deltaTime: c.float) -> ClayArray(RenderCommand) ---
|
||||||
|
GetOpenElementId :: proc() -> u32 ---
|
||||||
|
GetElementId :: proc(id: String) -> ElementId ---
|
||||||
|
GetElementIdWithIndex :: proc(id: String, index: u32) -> ElementId ---
|
||||||
|
GetElementData :: proc(id: ElementId) -> ElementData ---
|
||||||
|
Hovered :: proc() -> bool ---
|
||||||
|
OnHover :: proc(onHoverFunction: proc "c" (id: ElementId, pointerData: PointerData, userData: rawptr), userData: rawptr) ---
|
||||||
|
PointerOver :: proc(id: ElementId) -> bool ---
|
||||||
|
GetPointerOverIds :: proc() -> ElementIdArray ---
|
||||||
|
GetScrollOffset :: proc() -> Vector2 ---
|
||||||
|
GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData ---
|
||||||
|
SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: StringSlice, config: ^TextElementConfig, userData: rawptr) -> Dimensions, userData: rawptr) ---
|
||||||
|
SetQueryScrollOffsetFunction :: proc(queryScrollOffsetFunction: proc "c" (elementId: u32, userData: rawptr) -> Vector2, userData: rawptr) ---
|
||||||
|
RenderCommandArray_Get :: proc(array: ^ClayArray(RenderCommand), index: i32) -> ^RenderCommand ---
|
||||||
|
SetDebugModeEnabled :: proc(enabled: bool) ---
|
||||||
|
IsDebugModeEnabled :: proc() -> bool ---
|
||||||
|
SetCullingEnabled :: proc(enabled: bool) ---
|
||||||
|
GetMaxElementCount :: proc() -> i32 ---
|
||||||
|
SetMaxElementCount :: proc(maxElementCount: i32) ---
|
||||||
|
GetMaxMeasureTextCacheWordCount :: proc() -> i32 ---
|
||||||
|
SetMaxMeasureTextCacheWordCount :: proc(maxMeasureTextCacheWordCount: i32) ---
|
||||||
|
ResetMeasureTextCache :: proc() ---
|
||||||
|
EaseOut :: proc(arguments: TransitionCallbackArguments) -> bool ---
|
||||||
|
}
|
||||||
|
|
||||||
|
@(link_prefix = "Clay_", default_calling_convention = "c", private)
|
||||||
|
foreign Clay {
|
||||||
|
_ConfigureOpenElement :: proc(config: ElementDeclaration) ---
|
||||||
|
_HashString :: proc(key: String, seed: u32) -> ElementId ---
|
||||||
|
_HashStringWithOffset :: proc(key: String, index: u32, seed: u32) -> ElementId ---
|
||||||
|
_OpenTextElement :: proc(text: String, textConfig: TextElementConfig) ---
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigureOpenElement :: proc(config: ElementDeclaration) -> bool {
|
||||||
|
_ConfigureOpenElement(config)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
@(deferred_none = _CloseElement)
|
||||||
|
UI_WithId :: proc(id: ElementId) -> proc(config: ElementDeclaration) -> bool {
|
||||||
|
_OpenElementWithId(id)
|
||||||
|
return ConfigureOpenElement
|
||||||
|
}
|
||||||
|
|
||||||
|
@(deferred_none = _CloseElement)
|
||||||
|
UI_AutoId :: proc() -> proc(config: ElementDeclaration) -> bool {
|
||||||
|
_OpenElement()
|
||||||
|
return ConfigureOpenElement
|
||||||
|
}
|
||||||
|
|
||||||
|
UI :: proc {
|
||||||
|
UI_WithId,
|
||||||
|
UI_AutoId,
|
||||||
|
}
|
||||||
|
|
||||||
|
Text :: proc {
|
||||||
|
TextStatic,
|
||||||
|
TextDynamic,
|
||||||
|
}
|
||||||
|
|
||||||
|
TextStatic :: proc($text: string, config: TextElementConfig) {
|
||||||
|
wrapped := MakeString(text)
|
||||||
|
wrapped.isStaticallyAllocated = true
|
||||||
|
_OpenTextElement(wrapped, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextDynamic :: proc(text: string, config: TextElementConfig) {
|
||||||
|
_OpenTextElement(MakeString(text), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
PaddingAll :: proc(allPadding: u16) -> Padding {
|
||||||
|
return {left = allPadding, right = allPadding, top = allPadding, bottom = allPadding}
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderOutside :: proc(width: u16) -> BorderWidth {
|
||||||
|
return {width, width, width, width, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderAll :: proc(width: u16) -> BorderWidth {
|
||||||
|
return {width, width, width, width, width}
|
||||||
|
}
|
||||||
|
|
||||||
|
CornerRadiusAll :: proc(radius: f32) -> CornerRadius {
|
||||||
|
return CornerRadius{radius, radius, radius, radius}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingFit :: proc(sizeMinMax: SizingConstraintsMinMax = {}) -> SizingAxis {
|
||||||
|
return SizingAxis{type = SizingType.Fit, constraints = {sizeMinMax = sizeMinMax}}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingGrow :: proc(sizeMinMax: SizingConstraintsMinMax = {}) -> SizingAxis {
|
||||||
|
return SizingAxis{type = SizingType.Grow, constraints = {sizeMinMax = sizeMinMax}}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingFixed :: proc(size: c.float) -> SizingAxis {
|
||||||
|
return SizingAxis{type = SizingType.Fixed, constraints = {sizeMinMax = {size, size}}}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingPercent :: proc(sizePercent: c.float) -> SizingAxis {
|
||||||
|
return SizingAxis{type = SizingType.Percent, constraints = {sizePercent = sizePercent}}
|
||||||
|
}
|
||||||
|
|
||||||
|
MakeString :: proc(label: string) -> String {
|
||||||
|
return String{chars = raw_data(label), length = cast(c.int)len(label)}
|
||||||
|
}
|
||||||
|
|
||||||
|
ID :: proc(label: string, index: u32 = 0) -> ElementId {
|
||||||
|
return _HashString(MakeString(label), index)
|
||||||
|
}
|
||||||
|
|
||||||
|
ID_LOCAL :: proc(label: string, index: u32 = 0) -> ElementId {
|
||||||
|
return _HashStringWithOffset(MakeString(label), index, GetOpenElementId())
|
||||||
|
}
|
||||||
|
|
@ -10,11 +10,6 @@ import "base:runtime"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
|
|
||||||
WINDOW_WIDTH :: 1280
|
|
||||||
WINDOW_HEIGHT :: 720
|
|
||||||
WINDOW_FRAMERATE :: 30
|
|
||||||
WINDOW_CAPTION :: "Transformation Visualizer"
|
|
||||||
|
|
||||||
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||||
@(private="file") web_context: runtime.Context
|
@(private="file") web_context: runtime.Context
|
||||||
|
|
||||||
|
|
|
||||||
107
program.odin
107
program.odin
|
|
@ -1,3 +1,82 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import rl "libraries/raylib"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:strings"
|
||||||
|
import "core:mem"
|
||||||
|
import "base:runtime"
|
||||||
|
|
||||||
|
WINDOW_WIDTH :: 1280
|
||||||
|
WINDOW_HEIGHT :: 720
|
||||||
|
WINDOW_FRAMERATE :: 30
|
||||||
|
WINDOW_CAPTION :: "Transformation Visualizer"
|
||||||
|
|
||||||
|
v2 :: [2]f32
|
||||||
|
rect2 :: rl.Rectangle
|
||||||
|
|
||||||
|
UiElementType :: enum {
|
||||||
|
Input,
|
||||||
|
Button,
|
||||||
|
}
|
||||||
|
|
||||||
|
UiElementData :: union {
|
||||||
|
UiButtonData,
|
||||||
|
}
|
||||||
|
|
||||||
|
UiButtonData :: struct {
|
||||||
|
label: cstring,
|
||||||
|
}
|
||||||
|
|
||||||
|
UiElement :: struct {
|
||||||
|
area: rect2,
|
||||||
|
type: UiElementType,
|
||||||
|
data: UiElementData,
|
||||||
|
}
|
||||||
|
|
||||||
|
UiState :: struct {
|
||||||
|
origin, position: v2,
|
||||||
|
same_line: bool,
|
||||||
|
style: UiStyle,
|
||||||
|
elements: [dynamic]UiElement,
|
||||||
|
}
|
||||||
|
|
||||||
|
UiStyle :: struct {
|
||||||
|
margin, padding: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_button :: proc(state: ^UiState, size: v2, data: UiButtonData) {
|
||||||
|
element := UiElement{area = {**state.position, **size}, type = .Button, data = data}
|
||||||
|
if state.same_line {
|
||||||
|
state.position.x += size.x + state.style.padding
|
||||||
|
state.same_line = false
|
||||||
|
} else {
|
||||||
|
state.position.y += size.y + state.style.padding
|
||||||
|
}
|
||||||
|
append(&state.elements, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_same_line :: proc(state: ^UiState) {
|
||||||
|
state.same_line = true
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_start :: proc(state: ^UiState) {
|
||||||
|
clear(&state.elements)
|
||||||
|
state.position = state.origin + state.style.margin
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_end :: proc(state: UiState) -> []UiElement {
|
||||||
|
return state.elements[:]
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_init :: proc(state: ^UiState, style: UiStyle, origin: v2, allocator: mem.Allocator) {
|
||||||
|
state^ = {
|
||||||
|
origin = origin,
|
||||||
|
position = origin,
|
||||||
|
style = style,
|
||||||
|
elements = make(type_of(state.elements), 0, 512, allocator)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init :: proc() {
|
init :: proc() {
|
||||||
rl.SetTraceLogLevel(.WARNING)
|
rl.SetTraceLogLevel(.WARNING)
|
||||||
rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT})
|
rl.SetConfigFlags({.WINDOW_RESIZABLE, .VSYNC_HINT})
|
||||||
|
|
@ -6,10 +85,34 @@ init :: proc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
update :: proc() {
|
update :: proc() {
|
||||||
|
ui_style := UiStyle{margin = 4.0, padding = 4.0}
|
||||||
|
ui_state: UiState
|
||||||
|
ui_init(&ui_state, ui_style, {0, 0}, context.temp_allocator)
|
||||||
|
ui_start(&ui_state)
|
||||||
|
ui_button_size := v2{192.0, 32.0}
|
||||||
|
ui_same_line(&ui_state)
|
||||||
|
ui_button(&ui_state, ui_button_size, {label = "Hi"})
|
||||||
|
ui_same_line(&ui_state)
|
||||||
|
ui_button(&ui_state, ui_button_size, {label = "Hi"})
|
||||||
|
ui_same_line(&ui_state)
|
||||||
|
ui_button(&ui_state, ui_button_size, {label = "Hi"})
|
||||||
|
ui_elements := ui_end(ui_state)
|
||||||
|
|
||||||
rl.BeginDrawing()
|
rl.BeginDrawing()
|
||||||
|
defer rl.EndDrawing()
|
||||||
rl.ClearBackground(rl.BLACK)
|
rl.ClearBackground(rl.BLACK)
|
||||||
rl.DrawText("Hello world", 4, 4, 32, rl.WHITE)
|
|
||||||
rl.EndDrawing()
|
for element in ui_elements {
|
||||||
|
fmt.println(element)
|
||||||
|
switch element.type {
|
||||||
|
case .Button:
|
||||||
|
data := element.data.(UiButtonData)
|
||||||
|
rl.GuiButton(element.area, data.label)
|
||||||
|
case .Input:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.println()
|
||||||
|
|
||||||
free_all(context.temp_allocator)
|
free_all(context.temp_allocator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue