mirror of
https://github.com/nicbarker/clay.git
synced 2025-05-15 06:48:02 +00:00
Compare commits
9 Commits
5e8026be44
...
9fb7e1e2db
Author | SHA1 | Date | |
---|---|---|---|
|
9fb7e1e2db | ||
|
a60b977946 | ||
|
20340f6544 | ||
|
38bb241ced | ||
|
f4933c6669 | ||
|
61ba36753b | ||
|
4f4605eff9 | ||
|
7c65f31f46 | ||
|
01025e9157 |
5
.gitignore
vendored
5
.gitignore
vendored
@ -5,3 +5,8 @@ cmake-build-release/
|
|||||||
node_modules/
|
node_modules/
|
||||||
*.dSYM
|
*.dSYM
|
||||||
.vs/
|
.vs/
|
||||||
|
bindings/odin/clay-odin/tmp/
|
||||||
|
|
||||||
|
generator/__pycache__/
|
||||||
|
|
||||||
|
generator/generators/__pycache__/
|
||||||
|
@ -1,436 +1,459 @@
|
|||||||
package clay
|
package clay
|
||||||
|
|
||||||
import "core:c"
|
import "core:c"
|
||||||
import "core:strings"
|
|
||||||
|
|
||||||
when ODIN_OS == .Windows {
|
when ODIN_OS == .Windows {
|
||||||
foreign import Clay "windows/clay.lib"
|
foreign import Clay "windows/clay.lib"
|
||||||
} else when ODIN_OS == .Linux {
|
} else when ODIN_OS == .Linux {
|
||||||
foreign import Clay "linux/clay.a"
|
foreign import Clay "linux/clay.a"
|
||||||
} else when ODIN_OS == .Darwin {
|
} else when ODIN_OS == .Darwin {
|
||||||
when ODIN_ARCH == .arm64 {
|
when ODIN_ARCH == .arm64 {
|
||||||
foreign import Clay "macos-arm64/clay.a"
|
foreign import Clay "macos-arm64/clay.a"
|
||||||
} else {
|
} else {
|
||||||
foreign import Clay "macos/clay.a"
|
foreign import Clay "macos/clay.a"
|
||||||
}
|
}
|
||||||
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||||
foreign import Clay "wasm/clay.o"
|
foreign import Clay "wasm/clay.o"
|
||||||
}
|
}
|
||||||
|
|
||||||
String :: struct {
|
String :: struct {
|
||||||
length: c.int32_t,
|
length: c.int32_t,
|
||||||
chars: [^]c.char,
|
chars: [^]c.char,
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSlice :: struct {
|
StringSlice :: struct {
|
||||||
length: c.int32_t,
|
length: c.int32_t,
|
||||||
chars: [^]c.char,
|
chars: [^]c.char,
|
||||||
baseChars: [^]c.char,
|
baseChars: [^]c.char,
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 :: [2]c.float
|
Vector2 :: [2]c.float
|
||||||
|
|
||||||
Dimensions :: struct {
|
Dimensions :: struct {
|
||||||
width: c.float,
|
width: c.float,
|
||||||
height: c.float,
|
height: c.float,
|
||||||
}
|
}
|
||||||
|
|
||||||
Arena :: struct {
|
Arena :: struct {
|
||||||
nextAllocation: uintptr,
|
nextAllocation: uintptr,
|
||||||
capacity: uintptr,
|
capacity: uintptr,
|
||||||
memory: [^]c.char,
|
memory: [^]c.char,
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBox :: struct {
|
BoundingBox :: struct {
|
||||||
x: c.float,
|
x: c.float,
|
||||||
y: c.float,
|
y: c.float,
|
||||||
width: c.float,
|
width: c.float,
|
||||||
height: c.float,
|
height: c.float,
|
||||||
}
|
}
|
||||||
|
|
||||||
Color :: [4]c.float
|
Color :: [4]c.float
|
||||||
|
|
||||||
CornerRadius :: struct {
|
CornerRadius :: struct {
|
||||||
topLeft: c.float,
|
topLeft: c.float,
|
||||||
topRight: c.float,
|
topRight: c.float,
|
||||||
bottomLeft: c.float,
|
bottomLeft: c.float,
|
||||||
bottomRight: c.float,
|
bottomRight: c.float,
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderData :: struct {
|
BorderData :: struct {
|
||||||
width: u32,
|
width: u32,
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementId :: struct {
|
ElementId :: struct {
|
||||||
id: u32,
|
id: u32,
|
||||||
offset: u32,
|
offset: u32,
|
||||||
baseId: u32,
|
baseId: u32,
|
||||||
stringId: String,
|
stringId: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
when ODIN_OS == .Windows {
|
when ODIN_OS == .Windows {
|
||||||
EnumBackingType :: u32
|
EnumBackingType :: u32
|
||||||
} else {
|
} else {
|
||||||
EnumBackingType :: u8
|
EnumBackingType :: u8
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderCommandType :: enum EnumBackingType {
|
RenderCommandType :: enum EnumBackingType {
|
||||||
None,
|
None,
|
||||||
Rectangle,
|
Rectangle,
|
||||||
Border,
|
Border,
|
||||||
Text,
|
Text,
|
||||||
Image,
|
Image,
|
||||||
ScissorStart,
|
ScissorStart,
|
||||||
ScissorEnd,
|
ScissorEnd,
|
||||||
Custom,
|
Custom,
|
||||||
}
|
}
|
||||||
|
|
||||||
RectangleElementConfig :: struct {
|
RectangleElementConfig :: struct {
|
||||||
color: Color,
|
color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
TextWrapMode :: enum EnumBackingType {
|
TextWrapMode :: enum EnumBackingType {
|
||||||
Words,
|
Words,
|
||||||
Newlines,
|
Newlines,
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
TextAlignment :: enum EnumBackingType {
|
TextAlignment :: enum EnumBackingType {
|
||||||
Left,
|
Left,
|
||||||
Center,
|
Center,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
TextElementConfig :: struct {
|
TextElementConfig :: struct {
|
||||||
textColor: Color,
|
textColor: Color,
|
||||||
fontId: u16,
|
fontId: u16,
|
||||||
fontSize: u16,
|
fontSize: u16,
|
||||||
letterSpacing: u16,
|
letterSpacing: u16,
|
||||||
lineHeight: u16,
|
lineHeight: u16,
|
||||||
wrapMode: TextWrapMode,
|
wrapMode: TextWrapMode,
|
||||||
textAlignment: TextAlignment,
|
textAlignment: TextAlignment,
|
||||||
hashStringContents: bool,
|
hashStringContents: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageElementConfig :: struct {
|
ImageElementConfig :: struct {
|
||||||
imageData: rawptr,
|
imageData: rawptr,
|
||||||
sourceDimensions: Dimensions,
|
sourceDimensions: Dimensions,
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomElementConfig :: struct {
|
CustomElementConfig :: struct {
|
||||||
customData: rawptr,
|
customData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderWidth :: struct {
|
BorderWidth :: struct {
|
||||||
left: u16,
|
left: u16,
|
||||||
right: u16,
|
right: u16,
|
||||||
top: u16,
|
top: u16,
|
||||||
bottom: u16,
|
bottom: u16,
|
||||||
betweenChildren: u16,
|
betweenChildren: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderElementConfig :: struct {
|
BorderElementConfig :: struct {
|
||||||
color: Color,
|
color: Color,
|
||||||
width: BorderWidth,
|
width: BorderWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollElementConfig :: struct {
|
ScrollElementConfig :: struct {
|
||||||
horizontal: bool,
|
horizontal: bool,
|
||||||
vertical: bool,
|
vertical: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingAttachPointType :: enum EnumBackingType {
|
FloatingAttachPointType :: enum EnumBackingType {
|
||||||
LeftTop,
|
LeftTop,
|
||||||
LeftCenter,
|
LeftCenter,
|
||||||
LeftBottom,
|
LeftBottom,
|
||||||
CenterTop,
|
CenterTop,
|
||||||
CenterCenter,
|
CenterCenter,
|
||||||
CenterBottom,
|
CenterBottom,
|
||||||
RightTop,
|
RightTop,
|
||||||
RightCenter,
|
RightCenter,
|
||||||
RightBottom,
|
RightBottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingAttachPoints :: struct {
|
FloatingAttachPoints :: struct {
|
||||||
element: FloatingAttachPointType,
|
element: FloatingAttachPointType,
|
||||||
parent: FloatingAttachPointType,
|
parent: FloatingAttachPointType,
|
||||||
}
|
}
|
||||||
|
|
||||||
PointerCaptureMode :: enum EnumBackingType {
|
PointerCaptureMode :: enum EnumBackingType {
|
||||||
Capture,
|
Capture,
|
||||||
Passthrough,
|
Passthrough,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingAttachToElement :: enum EnumBackingType {
|
FloatingAttachToElement :: enum EnumBackingType {
|
||||||
None,
|
None,
|
||||||
Parent,
|
Parent,
|
||||||
ElementWithId,
|
ElementWithId,
|
||||||
Root,
|
Root,
|
||||||
}
|
}
|
||||||
|
|
||||||
FloatingElementConfig :: struct {
|
FloatingElementConfig :: struct {
|
||||||
offset: Vector2,
|
offset: Vector2,
|
||||||
expand: Dimensions,
|
expand: Dimensions,
|
||||||
parentId: u32,
|
parentId: u32,
|
||||||
zIndex: i32,
|
zIndex: i32,
|
||||||
attachment: FloatingAttachPoints,
|
attachment: FloatingAttachPoints,
|
||||||
pointerCaptureMode: PointerCaptureMode,
|
pointerCaptureMode: PointerCaptureMode,
|
||||||
attachTo: FloatingAttachToElement
|
attachTo: FloatingAttachToElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
TextRenderData :: struct {
|
TextRenderData :: struct {
|
||||||
stringContents: StringSlice,
|
stringContents: StringSlice,
|
||||||
textColor: Color,
|
textColor: Color,
|
||||||
fontId: u16,
|
fontId: u16,
|
||||||
fontSize: u16,
|
fontSize: u16,
|
||||||
letterSpacing: u16,
|
letterSpacing: u16,
|
||||||
lineHeight: u16,
|
lineHeight: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
RectangleRenderData :: struct {
|
RectangleRenderData :: struct {
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageRenderData :: struct {
|
ImageRenderData :: struct {
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
sourceDimensions: Dimensions,
|
sourceDimensions: Dimensions,
|
||||||
imageData: rawptr,
|
imageData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomRenderData :: struct {
|
CustomRenderData :: struct {
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
customData: rawptr,
|
customData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
BorderRenderData :: struct {
|
BorderRenderData :: struct {
|
||||||
color: Color,
|
color: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
width: BorderWidth,
|
width: BorderWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderCommandData :: struct #raw_union {
|
RenderCommandData :: struct #raw_union {
|
||||||
rectangle: RectangleRenderData,
|
rectangle: RectangleRenderData,
|
||||||
text: TextRenderData,
|
text: TextRenderData,
|
||||||
image: ImageRenderData,
|
image: ImageRenderData,
|
||||||
custom: CustomRenderData,
|
custom: CustomRenderData,
|
||||||
border: BorderRenderData,
|
border: BorderRenderData,
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderCommand :: struct {
|
RenderCommand :: struct {
|
||||||
boundingBox: BoundingBox,
|
boundingBox: BoundingBox,
|
||||||
renderData: RenderCommandData,
|
renderData: RenderCommandData,
|
||||||
userData: rawptr,
|
userData: rawptr,
|
||||||
id: u32,
|
id: u32,
|
||||||
zIndex: i16,
|
zIndex: i16,
|
||||||
commandType: RenderCommandType,
|
commandType: RenderCommandType,
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollContainerData :: struct {
|
ScrollContainerData :: struct {
|
||||||
// Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout.
|
// 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.
|
// Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
|
||||||
scrollPosition: ^Vector2,
|
scrollPosition: ^Vector2,
|
||||||
scrollContainerDimensions: Dimensions,
|
scrollContainerDimensions: Dimensions,
|
||||||
contentDimensions: Dimensions,
|
contentDimensions: Dimensions,
|
||||||
config: ScrollElementConfig,
|
config: ScrollElementConfig,
|
||||||
// Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
|
// Indicates whether an actual scroll container matched the provided ID or if the default struct was returned.
|
||||||
found: bool,
|
found: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
ElementData :: struct {
|
||||||
|
boundingBox: BoundingBox,
|
||||||
|
found: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerDataInteractionState :: enum EnumBackingType {
|
||||||
|
PressedThisFrame,
|
||||||
|
Pressed,
|
||||||
|
ReleasedThisFrame,
|
||||||
|
Released,
|
||||||
|
}
|
||||||
|
|
||||||
|
PointerData :: struct {
|
||||||
|
position: Vector2,
|
||||||
|
state: PointerDataInteractionState,
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingType :: enum EnumBackingType {
|
SizingType :: enum EnumBackingType {
|
||||||
Fit,
|
Fit,
|
||||||
Grow,
|
Grow,
|
||||||
Percent,
|
Percent,
|
||||||
Fixed,
|
Fixed,
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingConstraintsMinMax :: struct {
|
SizingConstraintsMinMax :: struct {
|
||||||
min: c.float,
|
min: c.float,
|
||||||
max: c.float,
|
max: c.float,
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingConstraints :: struct #raw_union {
|
SizingConstraints :: struct #raw_union {
|
||||||
sizeMinMax: SizingConstraintsMinMax,
|
sizeMinMax: SizingConstraintsMinMax,
|
||||||
sizePercent: c.float,
|
sizePercent: c.float,
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingAxis :: struct {
|
SizingAxis :: struct {
|
||||||
// Note: `min` is used for CLAY_SIZING_PERCENT, slightly different to clay.h due to lack of C anonymous unions
|
// Note: `min` is used for CLAY_SIZING_PERCENT, slightly different to clay.h due to lack of C anonymous unions
|
||||||
constraints: SizingConstraints,
|
constraints: SizingConstraints,
|
||||||
type: SizingType,
|
type: SizingType,
|
||||||
}
|
}
|
||||||
|
|
||||||
Sizing :: struct {
|
Sizing :: struct {
|
||||||
width: SizingAxis,
|
width: SizingAxis,
|
||||||
height: SizingAxis,
|
height: SizingAxis,
|
||||||
}
|
}
|
||||||
|
|
||||||
Padding :: struct {
|
Padding :: struct {
|
||||||
left: u16,
|
left: u16,
|
||||||
right: u16,
|
right: u16,
|
||||||
top: u16,
|
top: u16,
|
||||||
bottom: u16,
|
bottom: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutDirection :: enum EnumBackingType {
|
LayoutDirection :: enum EnumBackingType {
|
||||||
LeftToRight,
|
LeftToRight,
|
||||||
TopToBottom,
|
TopToBottom,
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutAlignmentX :: enum EnumBackingType {
|
LayoutAlignmentX :: enum EnumBackingType {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutAlignmentY :: enum EnumBackingType {
|
LayoutAlignmentY :: enum EnumBackingType {
|
||||||
Top,
|
Top,
|
||||||
Bottom,
|
Bottom,
|
||||||
Center,
|
Center,
|
||||||
}
|
}
|
||||||
|
|
||||||
ChildAlignment :: struct {
|
ChildAlignment :: struct {
|
||||||
x: LayoutAlignmentX,
|
x: LayoutAlignmentX,
|
||||||
y: LayoutAlignmentY,
|
y: LayoutAlignmentY,
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutConfig :: struct {
|
LayoutConfig :: struct {
|
||||||
sizing: Sizing,
|
sizing: Sizing,
|
||||||
padding: Padding,
|
padding: Padding,
|
||||||
childGap: u16,
|
childGap: u16,
|
||||||
childAlignment: ChildAlignment,
|
childAlignment: ChildAlignment,
|
||||||
layoutDirection: LayoutDirection,
|
layoutDirection: LayoutDirection,
|
||||||
}
|
}
|
||||||
|
|
||||||
ClayArray :: struct($type: typeid) {
|
ClayArray :: struct($type: typeid) {
|
||||||
capacity: i32,
|
capacity: i32,
|
||||||
length: i32,
|
length: i32,
|
||||||
internalArray: [^]type,
|
internalArray: [^]type,
|
||||||
}
|
}
|
||||||
|
|
||||||
ElementDeclaration :: struct {
|
ElementDeclaration :: struct {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
layout: LayoutConfig,
|
layout: LayoutConfig,
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
image: ImageElementConfig,
|
image: ImageElementConfig,
|
||||||
floating: FloatingElementConfig,
|
floating: FloatingElementConfig,
|
||||||
custom: CustomElementConfig,
|
custom: CustomElementConfig,
|
||||||
scroll: ScrollElementConfig,
|
scroll: ScrollElementConfig,
|
||||||
border: BorderElementConfig,
|
border: BorderElementConfig,
|
||||||
userData: rawptr
|
userData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorType :: enum EnumBackingType {
|
ErrorType :: enum EnumBackingType {
|
||||||
TextMeasurementFunctionNotProvided,
|
TextMeasurementFunctionNotProvided,
|
||||||
ArenaCapacityExceeded,
|
ArenaCapacityExceeded,
|
||||||
ElementsCapacityExceeded,
|
ElementsCapacityExceeded,
|
||||||
TextMeasurementCapacityExceeded,
|
TextMeasurementCapacityExceeded,
|
||||||
DuplicateId,
|
DuplicateId,
|
||||||
FloatingContainerParentNotFound,
|
FloatingContainerParentNotFound,
|
||||||
PercentageOver1,
|
PercentageOver1,
|
||||||
InternalError,
|
InternalError,
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorData :: struct {
|
ErrorData :: struct {
|
||||||
errorType: ErrorType,
|
errorType: ErrorType,
|
||||||
errorText: String,
|
errorText: String,
|
||||||
userData: rawptr
|
userData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorHandler :: struct {
|
ErrorHandler :: struct {
|
||||||
handler: proc "c" (errorData: ErrorData),
|
handler: proc "c" (errorData: ErrorData),
|
||||||
userData: rawptr
|
userData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
Context :: struct {} // opaque structure, only use as a pointer
|
Context :: struct {} // opaque structure, only use as a pointer
|
||||||
|
|
||||||
@(link_prefix = "Clay_", default_calling_convention = "c")
|
@(link_prefix = "Clay_", default_calling_convention = "c")
|
||||||
foreign Clay {
|
foreign Clay {
|
||||||
MinMemorySize :: proc() -> u32 ---
|
MinMemorySize :: proc() -> u32 ---
|
||||||
CreateArenaWithCapacityAndMemory :: proc(capacity: u32, offset: [^]u8) -> Arena ---
|
CreateArenaWithCapacityAndMemory :: proc(capacity: u32, offset: [^]u8) -> Arena ---
|
||||||
SetPointerState :: proc(position: Vector2, pointerDown: bool) ---
|
SetPointerState :: proc(position: Vector2, pointerDown: bool) ---
|
||||||
Initialize :: proc(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) ---
|
Initialize :: proc(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) -> ^Context ---
|
||||||
UpdateScrollContainers :: proc(enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: c.float) ---
|
GetCurrentContext :: proc() -> ^Context ---
|
||||||
SetLayoutDimensions :: proc(dimensions: Dimensions) ---
|
SetCurrentContext :: proc(ctx: ^Context) ---
|
||||||
BeginLayout :: proc() ---
|
UpdateScrollContainers :: proc(enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: c.float) ---
|
||||||
EndLayout :: proc() -> ClayArray(RenderCommand) ---
|
SetLayoutDimensions :: proc(dimensions: Dimensions) ---
|
||||||
Hovered :: proc() -> bool ---
|
BeginLayout :: proc() ---
|
||||||
PointerOver :: proc(id: ElementId) -> bool ---
|
EndLayout :: proc() -> ClayArray(RenderCommand) ---
|
||||||
GetElementId :: proc(id: String) -> ElementId ---
|
GetElementId :: proc(id: String) -> ElementId ---
|
||||||
GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData ---
|
GetElementIdWithIndex :: proc(id: String, index: u32) -> ElementId ---
|
||||||
SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: StringSlice, config: ^TextElementConfig, userData: uintptr) -> Dimensions, userData: uintptr) ---
|
GetElementData :: proc(id: ElementId) -> ElementData ---
|
||||||
RenderCommandArray_Get :: proc(array: ^ClayArray(RenderCommand), index: i32) -> ^RenderCommand ---
|
Hovered :: proc() -> bool ---
|
||||||
SetDebugModeEnabled :: proc(enabled: bool) ---
|
OnHover :: proc(onHoverFunction: proc "c" (id: ElementId, pointerData: PointerData, userData: rawptr), userData: rawptr) ---
|
||||||
GetCurrentContext :: proc() -> ^Context ---
|
PointerOver :: proc(id: ElementId) -> bool ---
|
||||||
SetCurrentContext :: proc(ctx: ^Context) ---
|
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() ---
|
||||||
}
|
}
|
||||||
|
|
||||||
@(link_prefix = "Clay_", default_calling_convention = "c", private)
|
@(link_prefix = "Clay_", default_calling_convention = "c", private)
|
||||||
foreign Clay {
|
foreign Clay {
|
||||||
_OpenElement :: proc() ---
|
_OpenElement :: proc() ---
|
||||||
_ConfigureOpenElement :: proc(config: ElementDeclaration) ---
|
_ConfigureOpenElement :: proc(config: ElementDeclaration) ---
|
||||||
_CloseElement :: proc() ---
|
_CloseElement :: proc() ---
|
||||||
_OpenTextElement :: proc(text: String, textConfig: ^TextElementConfig) ---
|
_HashString :: proc(key: String, offset: u32, seed: u32) -> ElementId ---
|
||||||
_StoreTextElementConfig :: proc(config: TextElementConfig) -> ^TextElementConfig ---
|
_OpenTextElement :: proc(text: String, textConfig: ^TextElementConfig) ---
|
||||||
_HashString :: proc(toHash: String, index: u32, seed: u32) -> ElementId ---
|
_StoreTextElementConfig :: proc(config: TextElementConfig) -> ^TextElementConfig ---
|
||||||
_GetOpenLayoutElementId :: proc() -> u32 ---
|
_GetParentElementId :: proc() -> u32 ---
|
||||||
}
|
|
||||||
|
|
||||||
ClayOpenElement :: struct {
|
|
||||||
configure: proc (config: ElementDeclaration) -> bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureOpenElement :: proc(config: ElementDeclaration) -> bool {
|
ConfigureOpenElement :: proc(config: ElementDeclaration) -> bool {
|
||||||
_ConfigureOpenElement(config)
|
_ConfigureOpenElement(config)
|
||||||
return true;
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_none = _CloseElement)
|
@(deferred_none = _CloseElement)
|
||||||
UI :: proc() -> ClayOpenElement {
|
UI :: proc() -> proc (config: ElementDeclaration) -> bool {
|
||||||
_OpenElement()
|
_OpenElement()
|
||||||
return { configure = ConfigureOpenElement }
|
return ConfigureOpenElement
|
||||||
}
|
}
|
||||||
|
|
||||||
Text :: proc(text: string, config: ^TextElementConfig) {
|
Text :: proc(text: string, config: ^TextElementConfig) {
|
||||||
_OpenTextElement(MakeString(text), config)
|
_OpenTextElement(MakeString(text), config)
|
||||||
}
|
}
|
||||||
|
|
||||||
TextConfig :: proc(config: TextElementConfig) -> ^TextElementConfig {
|
TextConfig :: proc(config: TextElementConfig) -> ^TextElementConfig {
|
||||||
return _StoreTextElementConfig(config)
|
return _StoreTextElementConfig(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
PaddingAll :: proc(allPadding: u16) -> Padding {
|
PaddingAll :: proc(allPadding: u16) -> Padding {
|
||||||
return { left = allPadding, right = allPadding, top = allPadding, bottom = allPadding }
|
return { left = allPadding, right = allPadding, top = allPadding, bottom = allPadding }
|
||||||
}
|
}
|
||||||
|
|
||||||
CornerRadiusAll :: proc(radius: f32) -> CornerRadius {
|
CornerRadiusAll :: proc(radius: f32) -> CornerRadius {
|
||||||
return CornerRadius{radius, radius, radius, radius}
|
return CornerRadius{radius, radius, radius, radius}
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingFit :: proc(sizeMinMax: SizingConstraintsMinMax) -> SizingAxis {
|
SizingFit :: proc(sizeMinMax: SizingConstraintsMinMax) -> SizingAxis {
|
||||||
return SizingAxis{type = SizingType.Fit, constraints = {sizeMinMax = sizeMinMax}}
|
return SizingAxis{type = SizingType.Fit, constraints = {sizeMinMax = sizeMinMax}}
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingGrow :: proc(sizeMinMax: SizingConstraintsMinMax) -> SizingAxis {
|
SizingGrow :: proc(sizeMinMax: SizingConstraintsMinMax) -> SizingAxis {
|
||||||
return SizingAxis{type = SizingType.Grow, constraints = {sizeMinMax = sizeMinMax}}
|
return SizingAxis{type = SizingType.Grow, constraints = {sizeMinMax = sizeMinMax}}
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingFixed :: proc(size: c.float) -> SizingAxis {
|
SizingFixed :: proc(size: c.float) -> SizingAxis {
|
||||||
return SizingAxis{type = SizingType.Fixed, constraints = {sizeMinMax = {size, size}}}
|
return SizingAxis{type = SizingType.Fixed, constraints = {sizeMinMax = {size, size}}}
|
||||||
}
|
}
|
||||||
|
|
||||||
SizingPercent :: proc(sizePercent: c.float) -> SizingAxis {
|
SizingPercent :: proc(sizePercent: c.float) -> SizingAxis {
|
||||||
return SizingAxis{type = SizingType.Percent, constraints = {sizePercent = sizePercent}}
|
return SizingAxis{type = SizingType.Percent, constraints = {sizePercent = sizePercent}}
|
||||||
}
|
}
|
||||||
|
|
||||||
MakeString :: proc(label: string) -> String {
|
MakeString :: proc(label: string) -> String {
|
||||||
return String{chars = raw_data(label), length = cast(c.int)len(label)}
|
return String{chars = raw_data(label), length = cast(c.int)len(label)}
|
||||||
}
|
}
|
||||||
|
|
||||||
ID :: proc(label: string, index: u32 = 0) -> ElementId {
|
ID :: proc(label: string, index: u32 = 0) -> ElementId {
|
||||||
return _HashString(MakeString(label), index, 0)
|
return _HashString(MakeString(label), index, 0)
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -63,13 +63,13 @@ border2pxRed := clay.BorderElementConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, text: string, image: ^raylib.Texture2D) {
|
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, text: string, image: ^raylib.Texture2D) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("HeroBlob", index),
|
id = clay.ID("HeroBlob", index),
|
||||||
layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } },
|
layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } },
|
||||||
border = border2pxRed,
|
border = border2pxRed,
|
||||||
cornerRadius = clay.CornerRadiusAll(10)
|
cornerRadius = clay.CornerRadiusAll(10)
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("CheckImage", index),
|
id = clay.ID("CheckImage", index),
|
||||||
layout = { sizing = { width = clay.SizingFixed(32) } },
|
layout = { sizing = { width = clay.SizingFixed(32) } },
|
||||||
image = { imageData = image, sourceDimensions = { 128, 128 } },
|
image = { imageData = image, sourceDimensions = { 128, 128 } },
|
||||||
@ -79,27 +79,27 @@ LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Colo
|
|||||||
}
|
}
|
||||||
|
|
||||||
LandingPageDesktop :: proc() {
|
LandingPageDesktop :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("LandingPage1Desktop"),
|
id = clay.ID("LandingPage1Desktop"),
|
||||||
layout = { sizing = { width = clay.SizingGrow({ }), height = clay.SizingFit({ min = cast(f32)windowHeight - 70 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
layout = { sizing = { width = clay.SizingGrow({ }), height = clay.SizingFit({ min = cast(f32)windowHeight - 70 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("LandingPage1"),
|
id = clay.ID("LandingPage1"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
||||||
border = { COLOR_RED, { left = 2, right = 2 } },
|
border = { COLOR_RED, { left = 2, right = 2 } },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({ id = clay.ID("LeftText"), layout = { sizing = { width = clay.SizingPercent(0.55) }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
if clay.UI()({ id = clay.ID("LeftText"), layout = { sizing = { width = clay.SizingPercent(0.55) }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.",
|
"Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.",
|
||||||
clay.TextConfig({fontSize = 56, fontId = FONT_ID_TITLE_56, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 56, fontId = FONT_ID_TITLE_56, textColor = COLOR_RED}),
|
||||||
)
|
)
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {}
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Clay is laying out this webpage right now!",
|
"Clay is laying out this webpage right now!",
|
||||||
clay.TextConfig({fontSize = 36, fontId = FONT_ID_TITLE_36, textColor = COLOR_ORANGE}),
|
clay.TextConfig({fontSize = 36, fontId = FONT_ID_TITLE_36, textColor = COLOR_ORANGE}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("HeroImageOuter"),
|
id = clay.ID("HeroImageOuter"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingPercent(0.45) }, childAlignment = { x = .Center }, childGap = 16 },
|
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingPercent(0.45) }, childAlignment = { x = .Center }, childGap = 16 },
|
||||||
}) {
|
}) {
|
||||||
@ -114,7 +114,7 @@ LandingPageDesktop :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
LandingPageMobile :: proc() {
|
LandingPageMobile :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("LandingPage1Mobile"),
|
id = clay.ID("LandingPage1Mobile"),
|
||||||
layout = {
|
layout = {
|
||||||
layoutDirection = .TopToBottom,
|
layoutDirection = .TopToBottom,
|
||||||
@ -124,18 +124,18 @@ LandingPageMobile :: proc() {
|
|||||||
childGap = 32,
|
childGap = 32,
|
||||||
},
|
},
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({ id = clay.ID("LeftText"), layout = { sizing = { width = clay.SizingGrow({ }) }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
if clay.UI()({ id = clay.ID("LeftText"), layout = { sizing = { width = clay.SizingGrow({ }) }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.",
|
"Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.",
|
||||||
clay.TextConfig({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}),
|
||||||
)
|
)
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {}
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Clay is laying out this webpage right now!",
|
"Clay is laying out this webpage right now!",
|
||||||
clay.TextConfig({fontSize = 32, fontId = FONT_ID_TITLE_32, textColor = COLOR_ORANGE}),
|
clay.TextConfig({fontSize = 32, fontId = FONT_ID_TITLE_32, textColor = COLOR_ORANGE}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("HeroImageOuter"),
|
id = clay.ID("HeroImageOuter"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow({ }) }, childAlignment = { x = .Center }, childGap = 16 },
|
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow({ }) }, childAlignment = { x = .Center }, childGap = 16 },
|
||||||
}) {
|
}) {
|
||||||
@ -150,17 +150,17 @@ LandingPageMobile :: proc() {
|
|||||||
|
|
||||||
FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) {
|
FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) {
|
||||||
textConfig := clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_RED})
|
textConfig := clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_RED})
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("HFileBoxOuter"),
|
id = clay.ID("HFileBoxOuter"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 },
|
layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({ id = clay.ID("HFileIncludeOuter"), layout = { padding = { 8, 8, 4, 4 } }, backgroundColor = COLOR_RED, cornerRadius = clay.CornerRadiusAll(8) }) {
|
if clay.UI()({ id = clay.ID("HFileIncludeOuter"), layout = { padding = { 8, 8, 4, 4 } }, backgroundColor = COLOR_RED, cornerRadius = clay.CornerRadiusAll(8) }) {
|
||||||
clay.Text("#include clay.h", clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_LIGHT}))
|
clay.Text("#include clay.h", clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_LIGHT}))
|
||||||
}
|
}
|
||||||
clay.Text("~2000 lines of C99.", textConfig)
|
clay.Text("~2000 lines of C99.", textConfig)
|
||||||
clay.Text("Zero dependencies, including no C standard library.", textConfig)
|
clay.Text("Zero dependencies, including no C standard library.", textConfig)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("BringYourOwnRendererOuter"),
|
id = clay.ID("BringYourOwnRendererOuter"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 },
|
layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 },
|
||||||
}) {
|
}) {
|
||||||
@ -171,8 +171,8 @@ FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FeatureBlocksDesktop :: proc() {
|
FeatureBlocksDesktop :: proc() {
|
||||||
if clay.UI().configure({ id = clay.ID("FeatureBlocksOuter"), layout = { sizing = { width = clay.SizingGrow({}) } } }) {
|
if clay.UI()({ id = clay.ID("FeatureBlocksOuter"), layout = { sizing = { width = clay.SizingGrow({}) } } }) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("FeatureBlocksInner"),
|
id = clay.ID("FeatureBlocksInner"),
|
||||||
layout = { sizing = { width = clay.SizingGrow({ }) }, childAlignment = { y = .Center } },
|
layout = { sizing = { width = clay.SizingGrow({ }) }, childAlignment = { y = .Center } },
|
||||||
border = { width = { betweenChildren = 2}, color = COLOR_RED },
|
border = { width = { betweenChildren = 2}, color = COLOR_RED },
|
||||||
@ -183,7 +183,7 @@ FeatureBlocksDesktop :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FeatureBlocksMobile :: proc() {
|
FeatureBlocksMobile :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("FeatureBlocksInner"),
|
id = clay.ID("FeatureBlocksInner"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow({ }) } },
|
layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow({ }) } },
|
||||||
border = { width = { betweenChildren = 2}, color = COLOR_RED },
|
border = { width = { betweenChildren = 2}, color = COLOR_RED },
|
||||||
@ -193,9 +193,9 @@ FeatureBlocksMobile :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
||||||
if clay.UI().configure({ id = clay.ID("SyntaxPageLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
if clay.UI()({ id = clay.ID("SyntaxPageLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||||
clay.Text("Declarative Syntax", clay.TextConfig(titleTextConfig))
|
clay.Text("Declarative Syntax", clay.TextConfig(titleTextConfig))
|
||||||
if clay.UI().configure({ id = clay.ID("SyntaxSpacer"), layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {}
|
if clay.UI()({ id = clay.ID("SyntaxSpacer"), layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {}
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Flexible and readable declarative syntax with nested UI element hierarchies.",
|
"Flexible and readable declarative syntax with nested UI element hierarchies.",
|
||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}),
|
||||||
@ -209,8 +209,8 @@ DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizi
|
|||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({ id = clay.ID("SyntaxPageRightImage"), layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) {
|
if clay.UI()({ id = clay.ID("SyntaxPageRightImage"), layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("SyntaxPageRightImageInner"),
|
id = clay.ID("SyntaxPageRightImageInner"),
|
||||||
layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } },
|
layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } },
|
||||||
image = { imageData = &syntaxImage, sourceDimensions = { 1136, 1194 } },
|
image = { imageData = &syntaxImage, sourceDimensions = { 1136, 1194 } },
|
||||||
@ -219,11 +219,11 @@ DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizi
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeclarativeSyntaxPageDesktop :: proc() {
|
DeclarativeSyntaxPageDesktop :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("SyntaxPageDesktop"),
|
id = clay.ID("SyntaxPageDesktop"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("SyntaxPage"),
|
id = clay.ID("SyntaxPage"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
||||||
border = border2pxRed,
|
border = border2pxRed,
|
||||||
@ -234,7 +234,7 @@ DeclarativeSyntaxPageDesktop :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeclarativeSyntaxPageMobile :: proc() {
|
DeclarativeSyntaxPageMobile :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("SyntaxPageMobile"),
|
id = clay.ID("SyntaxPageMobile"),
|
||||||
layout = {
|
layout = {
|
||||||
layoutDirection = .TopToBottom,
|
layoutDirection = .TopToBottom,
|
||||||
@ -255,9 +255,9 @@ ColorLerp :: proc(a: clay.Color, b: clay.Color, amount: f32) -> clay.Color {
|
|||||||
LOREM_IPSUM_TEXT := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
LOREM_IPSUM_TEXT := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||||
|
|
||||||
HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
||||||
if clay.UI().configure({ id = clay.ID("PerformanceLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
if clay.UI()({ id = clay.ID("PerformanceLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||||
clay.Text("High Performance", clay.TextConfig(titleTextConfig))
|
clay.Text("High Performance", clay.TextConfig(titleTextConfig))
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } }}) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } }}) {}
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Fast enough to recompute your entire UI every frame.",
|
"Fast enough to recompute your entire UI every frame.",
|
||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}),
|
||||||
@ -271,20 +271,20 @@ HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementCon
|
|||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({ id = clay.ID("PerformanceRightImageOuter"), layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) {
|
if clay.UI()({ id = clay.ID("PerformanceRightImageOuter"), layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("PerformanceRightBorder"),
|
id = clay.ID("PerformanceRightBorder"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(400) } },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(400) } },
|
||||||
border = { COLOR_LIGHT, {2, 2, 2, 2, 2} },
|
border = { COLOR_LIGHT, {2, 2, 2, 2, 2} },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("AnimationDemoContainerLeft"),
|
id = clay.ID("AnimationDemoContainerLeft"),
|
||||||
layout = { sizing = { clay.SizingPercent(0.35 + 0.3 * lerpValue), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(16) },
|
layout = { sizing = { clay.SizingPercent(0.35 + 0.3 * lerpValue), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(16) },
|
||||||
backgroundColor = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue),
|
backgroundColor = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue),
|
||||||
}) {
|
}) {
|
||||||
clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}))
|
clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}))
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("AnimationDemoContainerRight"),
|
id = clay.ID("AnimationDemoContainerRight"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(16) },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(16) },
|
||||||
backgroundColor = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue),
|
backgroundColor = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue),
|
||||||
@ -296,7 +296,7 @@ HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
HighPerformancePageDesktop :: proc(lerpValue: f32) {
|
HighPerformancePageDesktop :: proc(lerpValue: f32) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("PerformanceDesktop"),
|
id = clay.ID("PerformanceDesktop"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { 82, 82, 32, 32 }, childGap = 64 },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { 82, 82, 32, 32 }, childGap = 64 },
|
||||||
backgroundColor = COLOR_RED,
|
backgroundColor = COLOR_RED,
|
||||||
@ -306,7 +306,7 @@ HighPerformancePageDesktop :: proc(lerpValue: f32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HighPerformancePageMobile :: proc(lerpValue: f32) {
|
HighPerformancePageMobile :: proc(lerpValue: f32) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("PerformanceMobile"),
|
id = clay.ID("PerformanceMobile"),
|
||||||
layout = {
|
layout = {
|
||||||
layoutDirection = .TopToBottom,
|
layoutDirection = .TopToBottom,
|
||||||
@ -322,7 +322,7 @@ HighPerformancePageMobile :: proc(lerpValue: f32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererButtonActive :: proc(index: i32, text: string) {
|
RendererButtonActive :: proc(index: i32, text: string) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
|
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
|
||||||
backgroundColor = COLOR_RED,
|
backgroundColor = COLOR_RED,
|
||||||
cornerRadius = clay.CornerRadiusAll(10)
|
cornerRadius = clay.CornerRadiusAll(10)
|
||||||
@ -332,8 +332,8 @@ RendererButtonActive :: proc(index: i32, text: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererButtonInactive :: proc(index: u32, text: string) {
|
RendererButtonInactive :: proc(index: u32, text: string) {
|
||||||
if clay.UI().configure({ border = border2pxRed }) {
|
if clay.UI()({ border = border2pxRed }) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("RendererButtonInactiveInner", index),
|
id = clay.ID("RendererButtonInactiveInner", index),
|
||||||
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
|
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
|
||||||
backgroundColor = COLOR_LIGHT,
|
backgroundColor = COLOR_LIGHT,
|
||||||
@ -345,9 +345,9 @@ RendererButtonInactive :: proc(index: u32, text: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
RendererPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
||||||
if clay.UI().configure({ id = clay.ID("RendererLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
if clay.UI()({ id = clay.ID("RendererLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||||
clay.Text("Renderer & Platform Agnostic", clay.TextConfig(titleTextConfig))
|
clay.Text("Renderer & Platform Agnostic", clay.TextConfig(titleTextConfig))
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {}
|
||||||
clay.Text(
|
clay.Text(
|
||||||
"Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE.",
|
"Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE.",
|
||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}),
|
||||||
@ -361,22 +361,22 @@ RendererPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.
|
|||||||
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}),
|
clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("RendererRightText"),
|
id = clay.ID("RendererRightText"),
|
||||||
layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center }, layoutDirection = .TopToBottom, childGap = 16 },
|
layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center }, layoutDirection = .TopToBottom, childGap = 16 },
|
||||||
}) {
|
}) {
|
||||||
clay.Text("Try changing renderer!", clay.TextConfig({fontSize = 36, fontId = FONT_ID_BODY_36, textColor = COLOR_ORANGE}))
|
clay.Text("Try changing renderer!", clay.TextConfig({fontSize = 36, fontId = FONT_ID_BODY_36, textColor = COLOR_ORANGE}))
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({ max = 32 }) } } }) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 32 }) } } }) {}
|
||||||
RendererButtonActive(0, "Raylib Renderer")
|
RendererButtonActive(0, "Raylib Renderer")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RendererPageDesktop :: proc() {
|
RendererPageDesktop :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("RendererPageDesktop"),
|
id = clay.ID("RendererPageDesktop"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } },
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("RendererPage"),
|
id = clay.ID("RendererPage"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 },
|
||||||
border = { COLOR_RED, { left = 2, right = 2 } },
|
border = { COLOR_RED, { left = 2, right = 2 } },
|
||||||
@ -387,7 +387,7 @@ RendererPageDesktop :: proc() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RendererPageMobile :: proc() {
|
RendererPageMobile :: proc() {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("RendererMobile"),
|
id = clay.ID("RendererMobile"),
|
||||||
layout = {
|
layout = {
|
||||||
layoutDirection = .TopToBottom,
|
layoutDirection = .TopToBottom,
|
||||||
@ -414,27 +414,27 @@ animationLerpValue: f32 = -1.0
|
|||||||
createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
|
createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
|
||||||
mobileScreen := windowWidth < 750
|
mobileScreen := windowWidth < 750
|
||||||
clay.BeginLayout()
|
clay.BeginLayout()
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("OuterContainer"),
|
id = clay.ID("OuterContainer"),
|
||||||
layout = { layoutDirection = .TopToBottom, sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) } },
|
layout = { layoutDirection = .TopToBottom, sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) } },
|
||||||
backgroundColor = COLOR_LIGHT,
|
backgroundColor = COLOR_LIGHT,
|
||||||
}) {
|
}) {
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("Header"),
|
id = clay.ID("Header"),
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(50) }, childAlignment = { y = .Center }, childGap = 24, padding = { left = 32, right = 32 } },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(50) }, childAlignment = { y = .Center }, childGap = 24, padding = { left = 32, right = 32 } },
|
||||||
}) {
|
}) {
|
||||||
clay.Text("Clay", &headerTextConfig)
|
clay.Text("Clay", &headerTextConfig)
|
||||||
if clay.UI().configure({ layout = { sizing = { width = clay.SizingGrow({ }) } } }) {}
|
if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ }) } } }) {}
|
||||||
|
|
||||||
if (!mobileScreen) {
|
if (!mobileScreen) {
|
||||||
if clay.UI().configure({ id = clay.ID("LinkExamplesOuter"), backgroundColor = {0, 0, 0, 0} }) {
|
if clay.UI()({ id = clay.ID("LinkExamplesOuter"), backgroundColor = {0, 0, 0, 0} }) {
|
||||||
clay.Text("Examples", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
clay.Text("Examples", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
||||||
}
|
}
|
||||||
if clay.UI().configure({ id = clay.ID("LinkDocsOuter"), backgroundColor = {0, 0, 0, 0} }) {
|
if clay.UI()({ id = clay.ID("LinkDocsOuter"), backgroundColor = {0, 0, 0, 0} }) {
|
||||||
clay.Text("Docs", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
clay.Text("Docs", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("LinkGithubOuter"),
|
id = clay.ID("LinkGithubOuter"),
|
||||||
layout = { padding = { 16, 16, 6, 6 } },
|
layout = { padding = { 16, 16, 6, 6 } },
|
||||||
border = border2pxRed,
|
border = border2pxRed,
|
||||||
@ -444,12 +444,12 @@ createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
|
|||||||
clay.Text("Github", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
clay.Text("Github", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if clay.UI().configure({ id = clay.ID("TopBorder1"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_5 } ) {}
|
if clay.UI()({ id = clay.ID("TopBorder1"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_5 } ) {}
|
||||||
if clay.UI().configure({ id = clay.ID("TopBorder2"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_4 } ) {}
|
if clay.UI()({ id = clay.ID("TopBorder2"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_4 } ) {}
|
||||||
if clay.UI().configure({ id = clay.ID("TopBorder3"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_3 } ) {}
|
if clay.UI()({ id = clay.ID("TopBorder3"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_3 } ) {}
|
||||||
if clay.UI().configure({ id = clay.ID("TopBorder4"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_2 } ) {}
|
if clay.UI()({ id = clay.ID("TopBorder4"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_2 } ) {}
|
||||||
if clay.UI().configure({ id = clay.ID("TopBorder5"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_1 } ) {}
|
if clay.UI()({ id = clay.ID("TopBorder5"), layout = { sizing = { clay.SizingGrow({ }), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_1 } ) {}
|
||||||
if clay.UI().configure({
|
if clay.UI()({
|
||||||
id = clay.ID("ScrollContainerBackgroundRectangle"),
|
id = clay.ID("ScrollContainerBackgroundRectangle"),
|
||||||
scroll = { vertical = true },
|
scroll = { vertical = true },
|
||||||
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, layoutDirection = clay.LayoutDirection.TopToBottom },
|
layout = { sizing = { clay.SizingGrow({ }), clay.SizingGrow({ }) }, layoutDirection = clay.LayoutDirection.TopToBottom },
|
||||||
@ -493,7 +493,7 @@ main :: proc() {
|
|||||||
memory := make([^]u8, minMemorySize)
|
memory := make([^]u8, minMemorySize)
|
||||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
|
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
|
||||||
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
|
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
|
||||||
clay.SetMeasureTextFunction(measureText, 0)
|
clay.SetMeasureTextFunction(measureText, nil)
|
||||||
|
|
||||||
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT})
|
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT})
|
||||||
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")
|
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")
|
||||||
|
@ -16,7 +16,7 @@ clayColorToRaylibColor :: proc(color: clay.Color) -> raylib.Color {
|
|||||||
|
|
||||||
raylibFonts := [10]RaylibFont{}
|
raylibFonts := [10]RaylibFont{}
|
||||||
|
|
||||||
measureText :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: uintptr) -> clay.Dimensions {
|
measureText :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions {
|
||||||
// Measure string size for Font
|
// Measure string size for Font
|
||||||
textSize: clay.Dimensions = {0, 0}
|
textSize: clay.Dimensions = {0, 0}
|
||||||
|
|
||||||
|
2
clay.h
2
clay.h
@ -1918,7 +1918,7 @@ void Clay__ConfigureOpenElement(const Clay_ElementDeclaration declaration) {
|
|||||||
.clipElementId = clipElementId,
|
.clipElementId = clipElementId,
|
||||||
.zIndex = floatingConfig.zIndex,
|
.zIndex = floatingConfig.zIndex,
|
||||||
});
|
});
|
||||||
Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .floatingElementConfig = Clay__StoreFloatingElementConfig(declaration.floating) }, CLAY__ELEMENT_CONFIG_TYPE_FLOATING);
|
Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .floatingElementConfig = Clay__StoreFloatingElementConfig(floatingConfig) }, CLAY__ELEMENT_CONFIG_TYPE_FLOATING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (declaration.custom.customData) {
|
if (declaration.custom.customData) {
|
||||||
|
Binary file not shown.
0
generator/__init__.py
Normal file
0
generator/__init__.py
Normal file
83
generator/cli.py
Normal file
83
generator/cli.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import argparse
|
||||||
|
import logging
|
||||||
|
import json
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from generators.base_generator import BaseGenerator
|
||||||
|
from generators.odin_generator import OdinGenerator
|
||||||
|
from parser import parse_headers
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
GeneratorMap = dict[str, type[BaseGenerator]]
|
||||||
|
GENERATORS = {
|
||||||
|
'odin': OdinGenerator,
|
||||||
|
}
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
arg_parser = argparse.ArgumentParser(description='Generate clay bindings')
|
||||||
|
|
||||||
|
# Directories
|
||||||
|
arg_parser.add_argument('input_files', nargs='+', type=str, help='Input header files')
|
||||||
|
arg_parser.add_argument('--output-dir', type=str, help='Output directory', required=True)
|
||||||
|
arg_parser.add_argument('--tmp-dir', type=str, help='Temporary directory')
|
||||||
|
|
||||||
|
# Generators
|
||||||
|
arg_parser.add_argument('--generator', type=str, choices=list(GENERATORS.keys()), help='Generators to run', required=True)
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
arg_parser.add_argument('--verbose', action='store_true', help='Verbose logging')
|
||||||
|
|
||||||
|
args = arg_parser.parse_args()
|
||||||
|
|
||||||
|
log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||||
|
log_handler = logging.StreamHandler()
|
||||||
|
log_handler.setFormatter(log_formatter)
|
||||||
|
if args.verbose:
|
||||||
|
logging.basicConfig(level=logging.DEBUG, handlers=[log_handler])
|
||||||
|
else:
|
||||||
|
logging.basicConfig(level=logging.INFO, handlers=[log_handler])
|
||||||
|
|
||||||
|
output_dir = Path(args.output_dir)
|
||||||
|
output_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
if args.tmp_dir:
|
||||||
|
tmp_dir = Path(args.tmp_dir)
|
||||||
|
else:
|
||||||
|
tmp_dir = output_dir / 'tmp'
|
||||||
|
tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
fake_libc_include_path = Path(__file__).parent / 'fake_libc_include'
|
||||||
|
input_files = list(fake_libc_include_path.glob('*.h')) + [Path(f) for f in args.input_files]
|
||||||
|
|
||||||
|
logger.info(f'Input files: {input_files}')
|
||||||
|
logger.info(f'Output directory: {output_dir}')
|
||||||
|
logger.info(f'Temporary directory: {tmp_dir}')
|
||||||
|
logger.info(f'Generator: {args.generator}')
|
||||||
|
|
||||||
|
logger.info('Parsing headers')
|
||||||
|
extracted_symbols = parse_headers(input_files, tmp_dir)
|
||||||
|
with open(tmp_dir / 'extracted_symbols.json', 'w') as f:
|
||||||
|
f.write(json.dumps({
|
||||||
|
'structs': extracted_symbols.structs,
|
||||||
|
'enums': extracted_symbols.enums,
|
||||||
|
'functions': extracted_symbols.functions,
|
||||||
|
}, indent=2))
|
||||||
|
|
||||||
|
logger.info('Generating bindings')
|
||||||
|
generator = GENERATORS[args.generator](extracted_symbols)
|
||||||
|
generator.generate()
|
||||||
|
logger.debug(f'Generated bindings:')
|
||||||
|
# for file_name, content in generator.get_outputs().items():
|
||||||
|
# logger.debug(f'{file_name}:')
|
||||||
|
# logger.debug(content)
|
||||||
|
# logger.debug('\n')
|
||||||
|
|
||||||
|
tmp_outputs_dir = tmp_dir / 'generated'
|
||||||
|
tmp_outputs_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
generator.write_outputs(tmp_outputs_dir)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
262
generator/fake_libc_include/_fake_defines.h
Normal file
262
generator/fake_libc_include/_fake_defines.h
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
#ifndef _FAKE_DEFINES_H
|
||||||
|
#define _FAKE_DEFINES_H
|
||||||
|
|
||||||
|
#define NULL 0
|
||||||
|
#define BUFSIZ 1024
|
||||||
|
#define FOPEN_MAX 20
|
||||||
|
#define FILENAME_MAX 1024
|
||||||
|
|
||||||
|
#ifndef SEEK_SET
|
||||||
|
#define SEEK_SET 0 /* set file offset to offset */
|
||||||
|
#endif
|
||||||
|
#ifndef SEEK_CUR
|
||||||
|
#define SEEK_CUR 1 /* set file offset to current plus offset */
|
||||||
|
#endif
|
||||||
|
#ifndef SEEK_END
|
||||||
|
#define SEEK_END 2 /* set file offset to EOF plus offset */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __LITTLE_ENDIAN 1234
|
||||||
|
#define LITTLE_ENDIAN __LITTLE_ENDIAN
|
||||||
|
#define __BIG_ENDIAN 4321
|
||||||
|
#define BIG_ENDIAN __BIG_ENDIAN
|
||||||
|
#define __BYTE_ORDER __LITTLE_ENDIAN
|
||||||
|
#define BYTE_ORDER __BYTE_ORDER
|
||||||
|
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
|
||||||
|
#define SCHAR_MIN -128
|
||||||
|
#define SCHAR_MAX 127
|
||||||
|
#define CHAR_MIN -128
|
||||||
|
#define CHAR_MAX 127
|
||||||
|
#define UCHAR_MAX 255
|
||||||
|
#define SHRT_MIN -32768
|
||||||
|
#define SHRT_MAX 32767
|
||||||
|
#define USHRT_MAX 65535
|
||||||
|
#define INT_MIN -2147483648
|
||||||
|
#define INT_MAX 2147483647
|
||||||
|
#define UINT_MAX 4294967295U
|
||||||
|
#define LONG_MIN -9223372036854775808L
|
||||||
|
#define LONG_MAX 9223372036854775807L
|
||||||
|
#define ULONG_MAX 18446744073709551615UL
|
||||||
|
#define RAND_MAX 32767
|
||||||
|
|
||||||
|
/* C99 inttypes.h defines */
|
||||||
|
#define PRId8 "d"
|
||||||
|
#define PRIi8 "i"
|
||||||
|
#define PRIo8 "o"
|
||||||
|
#define PRIu8 "u"
|
||||||
|
#define PRIx8 "x"
|
||||||
|
#define PRIX8 "X"
|
||||||
|
#define PRId16 "d"
|
||||||
|
#define PRIi16 "i"
|
||||||
|
#define PRIo16 "o"
|
||||||
|
#define PRIu16 "u"
|
||||||
|
#define PRIx16 "x"
|
||||||
|
#define PRIX16 "X"
|
||||||
|
#define PRId32 "d"
|
||||||
|
#define PRIi32 "i"
|
||||||
|
#define PRIo32 "o"
|
||||||
|
#define PRIu32 "u"
|
||||||
|
#define PRIx32 "x"
|
||||||
|
#define PRIX32 "X"
|
||||||
|
#define PRId64 "d"
|
||||||
|
#define PRIi64 "i"
|
||||||
|
#define PRIo64 "o"
|
||||||
|
#define PRIu64 "u"
|
||||||
|
#define PRIx64 "x"
|
||||||
|
#define PRIX64 "X"
|
||||||
|
#define PRIdLEAST8 "d"
|
||||||
|
#define PRIiLEAST8 "i"
|
||||||
|
#define PRIoLEAST8 "o"
|
||||||
|
#define PRIuLEAST8 "u"
|
||||||
|
#define PRIxLEAST8 "x"
|
||||||
|
#define PRIXLEAST8 "X"
|
||||||
|
#define PRIdLEAST16 "d"
|
||||||
|
#define PRIiLEAST16 "i"
|
||||||
|
#define PRIoLEAST16 "o"
|
||||||
|
#define PRIuLEAST16 "u"
|
||||||
|
#define PRIxLEAST16 "x"
|
||||||
|
#define PRIXLEAST16 "X"
|
||||||
|
#define PRIdLEAST32 "d"
|
||||||
|
#define PRIiLEAST32 "i"
|
||||||
|
#define PRIoLEAST32 "o"
|
||||||
|
#define PRIuLEAST32 "u"
|
||||||
|
#define PRIxLEAST32 "x"
|
||||||
|
#define PRIXLEAST32 "X"
|
||||||
|
#define PRIdLEAST64 "d"
|
||||||
|
#define PRIiLEAST64 "i"
|
||||||
|
#define PRIoLEAST64 "o"
|
||||||
|
#define PRIuLEAST64 "u"
|
||||||
|
#define PRIxLEAST64 "x"
|
||||||
|
#define PRIXLEAST64 "X"
|
||||||
|
#define PRIdFAST8 "d"
|
||||||
|
#define PRIiFAST8 "i"
|
||||||
|
#define PRIoFAST8 "o"
|
||||||
|
#define PRIuFAST8 "u"
|
||||||
|
#define PRIxFAST8 "x"
|
||||||
|
#define PRIXFAST8 "X"
|
||||||
|
#define PRIdFAST16 "d"
|
||||||
|
#define PRIiFAST16 "i"
|
||||||
|
#define PRIoFAST16 "o"
|
||||||
|
#define PRIuFAST16 "u"
|
||||||
|
#define PRIxFAST16 "x"
|
||||||
|
#define PRIXFAST16 "X"
|
||||||
|
#define PRIdFAST32 "d"
|
||||||
|
#define PRIiFAST32 "i"
|
||||||
|
#define PRIoFAST32 "o"
|
||||||
|
#define PRIuFAST32 "u"
|
||||||
|
#define PRIxFAST32 "x"
|
||||||
|
#define PRIXFAST32 "X"
|
||||||
|
#define PRIdFAST64 "d"
|
||||||
|
#define PRIiFAST64 "i"
|
||||||
|
#define PRIoFAST64 "o"
|
||||||
|
#define PRIuFAST64 "u"
|
||||||
|
#define PRIxFAST64 "x"
|
||||||
|
#define PRIXFAST64 "X"
|
||||||
|
#define PRIdPTR "d"
|
||||||
|
#define PRIiPTR "i"
|
||||||
|
#define PRIoPTR "o"
|
||||||
|
#define PRIuPTR "u"
|
||||||
|
#define PRIxPTR "x"
|
||||||
|
#define PRIXPTR "X"
|
||||||
|
#define PRIdMAX "d"
|
||||||
|
#define PRIiMAX "i"
|
||||||
|
#define PRIoMAX "o"
|
||||||
|
#define PRIuMAX "u"
|
||||||
|
#define PRIxMAX "x"
|
||||||
|
#define PRIXMAX "X"
|
||||||
|
#define SCNd8 "d"
|
||||||
|
#define SCNi8 "i"
|
||||||
|
#define SCNo8 "o"
|
||||||
|
#define SCNu8 "u"
|
||||||
|
#define SCNx8 "x"
|
||||||
|
#define SCNd16 "d"
|
||||||
|
#define SCNi16 "i"
|
||||||
|
#define SCNo16 "o"
|
||||||
|
#define SCNu16 "u"
|
||||||
|
#define SCNx16 "x"
|
||||||
|
#define SCNd32 "d"
|
||||||
|
#define SCNi32 "i"
|
||||||
|
#define SCNo32 "o"
|
||||||
|
#define SCNu32 "u"
|
||||||
|
#define SCNx32 "x"
|
||||||
|
#define SCNd64 "d"
|
||||||
|
#define SCNi64 "i"
|
||||||
|
#define SCNo64 "o"
|
||||||
|
#define SCNu64 "u"
|
||||||
|
#define SCNx64 "x"
|
||||||
|
#define SCNdLEAST8 "d"
|
||||||
|
#define SCNiLEAST8 "i"
|
||||||
|
#define SCNoLEAST8 "o"
|
||||||
|
#define SCNuLEAST8 "u"
|
||||||
|
#define SCNxLEAST8 "x"
|
||||||
|
#define SCNdLEAST16 "d"
|
||||||
|
#define SCNiLEAST16 "i"
|
||||||
|
#define SCNoLEAST16 "o"
|
||||||
|
#define SCNuLEAST16 "u"
|
||||||
|
#define SCNxLEAST16 "x"
|
||||||
|
#define SCNdLEAST32 "d"
|
||||||
|
#define SCNiLEAST32 "i"
|
||||||
|
#define SCNoLEAST32 "o"
|
||||||
|
#define SCNuLEAST32 "u"
|
||||||
|
#define SCNxLEAST32 "x"
|
||||||
|
#define SCNdLEAST64 "d"
|
||||||
|
#define SCNiLEAST64 "i"
|
||||||
|
#define SCNoLEAST64 "o"
|
||||||
|
#define SCNuLEAST64 "u"
|
||||||
|
#define SCNxLEAST64 "x"
|
||||||
|
#define SCNdFAST8 "d"
|
||||||
|
#define SCNiFAST8 "i"
|
||||||
|
#define SCNoFAST8 "o"
|
||||||
|
#define SCNuFAST8 "u"
|
||||||
|
#define SCNxFAST8 "x"
|
||||||
|
#define SCNdFAST16 "d"
|
||||||
|
#define SCNiFAST16 "i"
|
||||||
|
#define SCNoFAST16 "o"
|
||||||
|
#define SCNuFAST16 "u"
|
||||||
|
#define SCNxFAST16 "x"
|
||||||
|
#define SCNdFAST32 "d"
|
||||||
|
#define SCNiFAST32 "i"
|
||||||
|
#define SCNoFAST32 "o"
|
||||||
|
#define SCNuFAST32 "u"
|
||||||
|
#define SCNxFAST32 "x"
|
||||||
|
#define SCNdFAST64 "d"
|
||||||
|
#define SCNiFAST64 "i"
|
||||||
|
#define SCNoFAST64 "o"
|
||||||
|
#define SCNuFAST64 "u"
|
||||||
|
#define SCNxFAST64 "x"
|
||||||
|
#define SCNdPTR "d"
|
||||||
|
#define SCNiPTR "i"
|
||||||
|
#define SCNoPTR "o"
|
||||||
|
#define SCNuPTR "u"
|
||||||
|
#define SCNxPTR "x"
|
||||||
|
#define SCNdMAX "d"
|
||||||
|
#define SCNiMAX "i"
|
||||||
|
#define SCNoMAX "o"
|
||||||
|
#define SCNuMAX "u"
|
||||||
|
#define SCNxMAX "x"
|
||||||
|
|
||||||
|
/* C99 stdbool.h defines */
|
||||||
|
#define __bool_true_false_are_defined 1
|
||||||
|
#define false 0
|
||||||
|
#define true 1
|
||||||
|
|
||||||
|
/* va_arg macros and type*/
|
||||||
|
#define va_start(_ap, _type) __builtin_va_start((_ap))
|
||||||
|
#define va_arg(_ap, _type) __builtin_va_arg((_ap))
|
||||||
|
#define va_end(_list)
|
||||||
|
|
||||||
|
/* Vectors */
|
||||||
|
#define __m128 int
|
||||||
|
#define __m128_u int
|
||||||
|
#define __m128d int
|
||||||
|
#define __m128d_u int
|
||||||
|
#define __m128i int
|
||||||
|
#define __m128i_u int
|
||||||
|
#define __m256 int
|
||||||
|
#define __m256_u int
|
||||||
|
#define __m256d int
|
||||||
|
#define __m256d_u int
|
||||||
|
#define __m256i int
|
||||||
|
#define __m256i_u int
|
||||||
|
#define __m512 int
|
||||||
|
#define __m512_u int
|
||||||
|
#define __m512d int
|
||||||
|
#define __m512d_u int
|
||||||
|
#define __m512i int
|
||||||
|
#define __m512i_u int
|
||||||
|
|
||||||
|
/* C11 stdnoreturn.h defines */
|
||||||
|
#define __noreturn_is_defined 1
|
||||||
|
#define noreturn _Noreturn
|
||||||
|
|
||||||
|
/* C11 threads.h defines */
|
||||||
|
#define thread_local _Thread_local
|
||||||
|
|
||||||
|
/* C11 assert.h defines */
|
||||||
|
#define static_assert _Static_assert
|
||||||
|
|
||||||
|
/* C11 stdatomic.h defines */
|
||||||
|
#define ATOMIC_BOOL_LOCK_FREE 0
|
||||||
|
#define ATOMIC_CHAR_LOCK_FREE 0
|
||||||
|
#define ATOMIC_CHAR16_T_LOCK_FREE 0
|
||||||
|
#define ATOMIC_CHAR32_T_LOCK_FREE 0
|
||||||
|
#define ATOMIC_WCHAR_T_LOCK_FREE 0
|
||||||
|
#define ATOMIC_SHORT_LOCK_FREE 0
|
||||||
|
#define ATOMIC_INT_LOCK_FREE 0
|
||||||
|
#define ATOMIC_LONG_LOCK_FREE 0
|
||||||
|
#define ATOMIC_LLONG_LOCK_FREE 0
|
||||||
|
#define ATOMIC_POINTER_LOCK_FREE 0
|
||||||
|
#define ATOMIC_VAR_INIT(value) (value)
|
||||||
|
#define ATOMIC_FLAG_INIT { 0 }
|
||||||
|
#define kill_dependency(y) (y)
|
||||||
|
|
||||||
|
/* C11 stdalign.h defines */
|
||||||
|
#define alignas _Alignas
|
||||||
|
#define alignof _Alignof
|
||||||
|
#define __alignas_is_defined 1
|
||||||
|
#define __alignof_is_defined 1
|
||||||
|
|
||||||
|
#endif
|
222
generator/fake_libc_include/_fake_typedefs.h
Normal file
222
generator/fake_libc_include/_fake_typedefs.h
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
#ifndef _FAKE_TYPEDEFS_H
|
||||||
|
#define _FAKE_TYPEDEFS_H
|
||||||
|
|
||||||
|
typedef int size_t;
|
||||||
|
typedef int __builtin_va_list;
|
||||||
|
typedef int __gnuc_va_list;
|
||||||
|
typedef int va_list;
|
||||||
|
typedef int __int8_t;
|
||||||
|
typedef int __uint8_t;
|
||||||
|
typedef int __int16_t;
|
||||||
|
typedef int __uint16_t;
|
||||||
|
typedef int __int_least16_t;
|
||||||
|
typedef int __uint_least16_t;
|
||||||
|
typedef int __int32_t;
|
||||||
|
typedef int __uint32_t;
|
||||||
|
typedef int __int64_t;
|
||||||
|
typedef int __uint64_t;
|
||||||
|
typedef int __int_least32_t;
|
||||||
|
typedef int __uint_least32_t;
|
||||||
|
typedef int __s8;
|
||||||
|
typedef int __u8;
|
||||||
|
typedef int __s16;
|
||||||
|
typedef int __u16;
|
||||||
|
typedef int __s32;
|
||||||
|
typedef int __u32;
|
||||||
|
typedef int __s64;
|
||||||
|
typedef int __u64;
|
||||||
|
typedef int _LOCK_T;
|
||||||
|
typedef int _LOCK_RECURSIVE_T;
|
||||||
|
typedef int _off_t;
|
||||||
|
typedef int __dev_t;
|
||||||
|
typedef int __uid_t;
|
||||||
|
typedef int __gid_t;
|
||||||
|
typedef int _off64_t;
|
||||||
|
typedef int _fpos_t;
|
||||||
|
typedef int _ssize_t;
|
||||||
|
typedef int wint_t;
|
||||||
|
typedef int _mbstate_t;
|
||||||
|
typedef int _flock_t;
|
||||||
|
typedef int _iconv_t;
|
||||||
|
typedef int __ULong;
|
||||||
|
typedef int __FILE;
|
||||||
|
typedef int ptrdiff_t;
|
||||||
|
typedef int wchar_t;
|
||||||
|
typedef int char16_t;
|
||||||
|
typedef int char32_t;
|
||||||
|
typedef int __off_t;
|
||||||
|
typedef int __pid_t;
|
||||||
|
typedef int __loff_t;
|
||||||
|
typedef int u_char;
|
||||||
|
typedef int u_short;
|
||||||
|
typedef int u_int;
|
||||||
|
typedef int u_long;
|
||||||
|
typedef int ushort;
|
||||||
|
typedef int uint;
|
||||||
|
typedef int clock_t;
|
||||||
|
typedef int time_t;
|
||||||
|
typedef int daddr_t;
|
||||||
|
typedef int caddr_t;
|
||||||
|
typedef int ino_t;
|
||||||
|
typedef int off_t;
|
||||||
|
typedef int dev_t;
|
||||||
|
typedef int uid_t;
|
||||||
|
typedef int gid_t;
|
||||||
|
typedef int pid_t;
|
||||||
|
typedef int key_t;
|
||||||
|
typedef int ssize_t;
|
||||||
|
typedef int mode_t;
|
||||||
|
typedef int nlink_t;
|
||||||
|
typedef int fd_mask;
|
||||||
|
typedef int _types_fd_set;
|
||||||
|
typedef int clockid_t;
|
||||||
|
typedef int timer_t;
|
||||||
|
typedef int useconds_t;
|
||||||
|
typedef int suseconds_t;
|
||||||
|
typedef int FILE;
|
||||||
|
typedef int fpos_t;
|
||||||
|
typedef int cookie_read_function_t;
|
||||||
|
typedef int cookie_write_function_t;
|
||||||
|
typedef int cookie_seek_function_t;
|
||||||
|
typedef int cookie_close_function_t;
|
||||||
|
typedef int cookie_io_functions_t;
|
||||||
|
typedef int div_t;
|
||||||
|
typedef int ldiv_t;
|
||||||
|
typedef int lldiv_t;
|
||||||
|
typedef int sigset_t;
|
||||||
|
typedef int __sigset_t;
|
||||||
|
typedef int _sig_func_ptr;
|
||||||
|
typedef int sig_atomic_t;
|
||||||
|
typedef int __tzrule_type;
|
||||||
|
typedef int __tzinfo_type;
|
||||||
|
typedef int mbstate_t;
|
||||||
|
typedef int sem_t;
|
||||||
|
typedef int pthread_t;
|
||||||
|
typedef int pthread_attr_t;
|
||||||
|
typedef int pthread_mutex_t;
|
||||||
|
typedef int pthread_mutexattr_t;
|
||||||
|
typedef int pthread_cond_t;
|
||||||
|
typedef int pthread_condattr_t;
|
||||||
|
typedef int pthread_key_t;
|
||||||
|
typedef int pthread_once_t;
|
||||||
|
typedef int pthread_rwlock_t;
|
||||||
|
typedef int pthread_rwlockattr_t;
|
||||||
|
typedef int pthread_spinlock_t;
|
||||||
|
typedef int pthread_barrier_t;
|
||||||
|
typedef int pthread_barrierattr_t;
|
||||||
|
typedef int jmp_buf;
|
||||||
|
typedef int rlim_t;
|
||||||
|
typedef int sa_family_t;
|
||||||
|
typedef int sigjmp_buf;
|
||||||
|
typedef int stack_t;
|
||||||
|
typedef int siginfo_t;
|
||||||
|
typedef int z_stream;
|
||||||
|
|
||||||
|
/* C99 exact-width integer types */
|
||||||
|
typedef int int8_t;
|
||||||
|
typedef int uint8_t;
|
||||||
|
typedef int int16_t;
|
||||||
|
typedef int uint16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef int uint32_t;
|
||||||
|
typedef int int64_t;
|
||||||
|
typedef int uint64_t;
|
||||||
|
|
||||||
|
/* C99 minimum-width integer types */
|
||||||
|
typedef int int_least8_t;
|
||||||
|
typedef int uint_least8_t;
|
||||||
|
typedef int int_least16_t;
|
||||||
|
typedef int uint_least16_t;
|
||||||
|
typedef int int_least32_t;
|
||||||
|
typedef int uint_least32_t;
|
||||||
|
typedef int int_least64_t;
|
||||||
|
typedef int uint_least64_t;
|
||||||
|
|
||||||
|
/* C99 fastest minimum-width integer types */
|
||||||
|
typedef int int_fast8_t;
|
||||||
|
typedef int uint_fast8_t;
|
||||||
|
typedef int int_fast16_t;
|
||||||
|
typedef int uint_fast16_t;
|
||||||
|
typedef int int_fast32_t;
|
||||||
|
typedef int uint_fast32_t;
|
||||||
|
typedef int int_fast64_t;
|
||||||
|
typedef int uint_fast64_t;
|
||||||
|
|
||||||
|
/* C99 integer types capable of holding object pointers */
|
||||||
|
typedef int intptr_t;
|
||||||
|
typedef int uintptr_t;
|
||||||
|
|
||||||
|
/* C99 greatest-width integer types */
|
||||||
|
typedef int intmax_t;
|
||||||
|
typedef int uintmax_t;
|
||||||
|
|
||||||
|
/* C99 stdbool.h bool type. _Bool is built-in in C99 */
|
||||||
|
typedef _Bool bool;
|
||||||
|
|
||||||
|
/* Mir typedefs */
|
||||||
|
typedef void* MirEGLNativeWindowType;
|
||||||
|
typedef void* MirEGLNativeDisplayType;
|
||||||
|
typedef struct MirConnection MirConnection;
|
||||||
|
typedef struct MirSurface MirSurface;
|
||||||
|
typedef struct MirSurfaceSpec MirSurfaceSpec;
|
||||||
|
typedef struct MirScreencast MirScreencast;
|
||||||
|
typedef struct MirPromptSession MirPromptSession;
|
||||||
|
typedef struct MirBufferStream MirBufferStream;
|
||||||
|
typedef struct MirPersistentId MirPersistentId;
|
||||||
|
typedef struct MirBlob MirBlob;
|
||||||
|
typedef struct MirDisplayConfig MirDisplayConfig;
|
||||||
|
|
||||||
|
/* xcb typedefs */
|
||||||
|
typedef struct xcb_connection_t xcb_connection_t;
|
||||||
|
typedef uint32_t xcb_window_t;
|
||||||
|
typedef uint32_t xcb_visualid_t;
|
||||||
|
|
||||||
|
/* C11 stdatomic.h types */
|
||||||
|
typedef _Atomic(_Bool) atomic_bool;
|
||||||
|
typedef _Atomic(char) atomic_char;
|
||||||
|
typedef _Atomic(signed char) atomic_schar;
|
||||||
|
typedef _Atomic(unsigned char) atomic_uchar;
|
||||||
|
typedef _Atomic(short) atomic_short;
|
||||||
|
typedef _Atomic(unsigned short) atomic_ushort;
|
||||||
|
typedef _Atomic(int) atomic_int;
|
||||||
|
typedef _Atomic(unsigned int) atomic_uint;
|
||||||
|
typedef _Atomic(long) atomic_long;
|
||||||
|
typedef _Atomic(unsigned long) atomic_ulong;
|
||||||
|
typedef _Atomic(long long) atomic_llong;
|
||||||
|
typedef _Atomic(unsigned long long) atomic_ullong;
|
||||||
|
typedef _Atomic(uint_least16_t) atomic_char16_t;
|
||||||
|
typedef _Atomic(uint_least32_t) atomic_char32_t;
|
||||||
|
typedef _Atomic(wchar_t) atomic_wchar_t;
|
||||||
|
typedef _Atomic(int_least8_t) atomic_int_least8_t;
|
||||||
|
typedef _Atomic(uint_least8_t) atomic_uint_least8_t;
|
||||||
|
typedef _Atomic(int_least16_t) atomic_int_least16_t;
|
||||||
|
typedef _Atomic(uint_least16_t) atomic_uint_least16_t;
|
||||||
|
typedef _Atomic(int_least32_t) atomic_int_least32_t;
|
||||||
|
typedef _Atomic(uint_least32_t) atomic_uint_least32_t;
|
||||||
|
typedef _Atomic(int_least64_t) atomic_int_least64_t;
|
||||||
|
typedef _Atomic(uint_least64_t) atomic_uint_least64_t;
|
||||||
|
typedef _Atomic(int_fast8_t) atomic_int_fast8_t;
|
||||||
|
typedef _Atomic(uint_fast8_t) atomic_uint_fast8_t;
|
||||||
|
typedef _Atomic(int_fast16_t) atomic_int_fast16_t;
|
||||||
|
typedef _Atomic(uint_fast16_t) atomic_uint_fast16_t;
|
||||||
|
typedef _Atomic(int_fast32_t) atomic_int_fast32_t;
|
||||||
|
typedef _Atomic(uint_fast32_t) atomic_uint_fast32_t;
|
||||||
|
typedef _Atomic(int_fast64_t) atomic_int_fast64_t;
|
||||||
|
typedef _Atomic(uint_fast64_t) atomic_uint_fast64_t;
|
||||||
|
typedef _Atomic(intptr_t) atomic_intptr_t;
|
||||||
|
typedef _Atomic(uintptr_t) atomic_uintptr_t;
|
||||||
|
typedef _Atomic(size_t) atomic_size_t;
|
||||||
|
typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t;
|
||||||
|
typedef _Atomic(intmax_t) atomic_intmax_t;
|
||||||
|
typedef _Atomic(uintmax_t) atomic_uintmax_t;
|
||||||
|
typedef struct atomic_flag { atomic_bool _Value; } atomic_flag;
|
||||||
|
typedef enum memory_order {
|
||||||
|
memory_order_relaxed,
|
||||||
|
memory_order_consume,
|
||||||
|
memory_order_acquire,
|
||||||
|
memory_order_release,
|
||||||
|
memory_order_acq_rel,
|
||||||
|
memory_order_seq_cst
|
||||||
|
} memory_order;
|
||||||
|
|
||||||
|
#endif
|
2
generator/fake_libc_include/_syslist.h
Normal file
2
generator/fake_libc_include/_syslist.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "_fake_defines.h"
|
||||||
|
#include "_fake_typedefs.h"
|
2
generator/fake_libc_include/stdbool.h
Normal file
2
generator/fake_libc_include/stdbool.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "_fake_defines.h"
|
||||||
|
#include "_fake_typedefs.h"
|
2
generator/fake_libc_include/stddef.h
Normal file
2
generator/fake_libc_include/stddef.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "_fake_defines.h"
|
||||||
|
#include "_fake_typedefs.h"
|
2
generator/fake_libc_include/stdint.h
Normal file
2
generator/fake_libc_include/stdint.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#include "_fake_defines.h"
|
||||||
|
#include "_fake_typedefs.h"
|
5
generator/gen_repo_bindings.sh
Normal file
5
generator/gen_repo_bindings.sh
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
REPO_ROOT=$(realpath $(dirname $(dirname $0)))
|
||||||
|
|
||||||
|
# Generate odin bindings
|
||||||
|
python $REPO_ROOT/generator/cli.py $REPO_ROOT/clay.h --output-dir $REPO_ROOT/bindings/odin/clay-odin --generator odin --verbose
|
0
generator/generators/__init__.py
Normal file
0
generator/generators/__init__.py
Normal file
47
generator/generators/base_generator.py
Normal file
47
generator/generators/base_generator.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
from parser import ExtractedSymbols, ExtractedEnum, ExtractedStruct, ExtractedFunction
|
||||||
|
from typing import Any, Callable, DefaultDict, Literal, NotRequired, Optional, TypedDict
|
||||||
|
from pathlib import Path
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
SymbolType = Literal['enum', 'struct', 'function']
|
||||||
|
|
||||||
|
class BaseGenerator:
|
||||||
|
def __init__(self, extracted_symbols: ExtractedSymbols):
|
||||||
|
self.extracted_symbols = extracted_symbols
|
||||||
|
self.output_content: dict[str, list[str]] = dict()
|
||||||
|
|
||||||
|
def generate(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def has_symbol(self, symbol: str) -> bool:
|
||||||
|
return (
|
||||||
|
symbol in self.extracted_symbols.enums or
|
||||||
|
symbol in self.extracted_symbols.structs or
|
||||||
|
symbol in self.extracted_symbols.functions
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_symbol_type(self, symbol: str) -> SymbolType:
|
||||||
|
if symbol in self.extracted_symbols.enums:
|
||||||
|
return 'enum'
|
||||||
|
elif symbol in self.extracted_symbols.structs:
|
||||||
|
return 'struct'
|
||||||
|
elif symbol in self.extracted_symbols.functions:
|
||||||
|
return 'function'
|
||||||
|
raise ValueError(f'Unknown symbol: {symbol}')
|
||||||
|
|
||||||
|
def _write(self, file_name: str, content: str) -> None:
|
||||||
|
if file_name not in self.output_content:
|
||||||
|
self.output_content[file_name] = []
|
||||||
|
self.output_content[file_name].append(content)
|
||||||
|
|
||||||
|
def write_outputs(self, output_dir: Path) -> None:
|
||||||
|
for file_name, content in self.output_content.items():
|
||||||
|
(output_dir / file_name).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
with open(output_dir / file_name, 'w') as f:
|
||||||
|
f.write("\n".join(content))
|
||||||
|
|
||||||
|
def get_outputs(self) -> dict[str, str]:
|
||||||
|
return {file_name: "\n".join(content) for file_name, content in self.output_content.items()}
|
||||||
|
|
||||||
|
|
164
generator/generators/odin/clay.template.odin
Normal file
164
generator/generators/odin/clay.template.odin
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
package clay
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
import "core:strings"
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
|
foreign import Clay "windows/clay.lib"
|
||||||
|
} else when ODIN_OS == .Linux {
|
||||||
|
foreign import Clay "linux/clay.a"
|
||||||
|
} else when ODIN_OS == .Darwin {
|
||||||
|
when ODIN_ARCH == .arm64 {
|
||||||
|
foreign import Clay "macos-arm64/clay.a"
|
||||||
|
} else {
|
||||||
|
foreign import Clay "macos/clay.a"
|
||||||
|
}
|
||||||
|
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
|
||||||
|
foreign import Clay "wasm/clay.o"
|
||||||
|
}
|
||||||
|
|
||||||
|
when ODIN_OS == .Windows {
|
||||||
|
EnumBackingType :: u32
|
||||||
|
} else {
|
||||||
|
EnumBackingType :: u8
|
||||||
|
}
|
||||||
|
|
||||||
|
{{enums}}
|
||||||
|
|
||||||
|
Context :: struct {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ClayArray :: struct($type: typeid) {
|
||||||
|
capacity: i32,
|
||||||
|
length: i32,
|
||||||
|
internalArray: [^]type,
|
||||||
|
}
|
||||||
|
|
||||||
|
SizingConstraints :: struct #raw_union {
|
||||||
|
sizeMinMax: SizingConstraintsMinMax,
|
||||||
|
sizePercent: c.float,
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedConfig :: struct {
|
||||||
|
type: ElementConfigType,
|
||||||
|
config: rawptr,
|
||||||
|
id: ElementId,
|
||||||
|
}
|
||||||
|
|
||||||
|
{{structs}}
|
||||||
|
|
||||||
|
@(link_prefix = "Clay_", default_calling_convention = "c")
|
||||||
|
foreign Clay {
|
||||||
|
{{public_functions}}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(link_prefix = "Clay_", default_calling_convention = "c", private)
|
||||||
|
foreign Clay {
|
||||||
|
{{private_functions}}
|
||||||
|
}
|
||||||
|
|
||||||
|
@(require_results, deferred_none = _CloseElement)
|
||||||
|
UI :: proc(configs: ..TypedConfig) -> bool {
|
||||||
|
_OpenElement()
|
||||||
|
for config in configs {
|
||||||
|
#partial switch (config.type) {
|
||||||
|
case ElementConfigType.Id:
|
||||||
|
_AttachId(config.id)
|
||||||
|
case ElementConfigType.Layout:
|
||||||
|
_AttachLayoutConfig(cast(^LayoutConfig)config.config)
|
||||||
|
case:
|
||||||
|
_AttachElementConfig(config.config, config.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ElementPostConfiguration()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout :: proc(config: LayoutConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Layout, config = _StoreLayoutConfig(config) }
|
||||||
|
}
|
||||||
|
|
||||||
|
PaddingAll :: proc (padding: u16) -> Padding {
|
||||||
|
return { padding, padding, padding, padding }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle :: proc(config: RectangleElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Rectangle, config = _StoreRectangleElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text :: proc(text: string, config: ^TextElementConfig) {
|
||||||
|
_OpenTextElement(MakeString(text), config)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextConfig :: proc(config: TextElementConfig) -> ^TextElementConfig {
|
||||||
|
return _StoreTextElementConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
Image :: proc(config: ImageElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Image, config = _StoreImageElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Floating :: proc(config: FloatingElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Floating, config = _StoreFloatingElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Custom :: proc(config: CustomElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Custom, config = _StoreCustomElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Scroll :: proc(config: ScrollElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Scroll, config = _StoreScrollElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Border :: proc(config: BorderElementConfig) -> TypedConfig {
|
||||||
|
return {type = ElementConfigType.Border, config = _StoreBorderElementConfig(config)}
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderOutside :: proc(outsideBorders: BorderData) -> TypedConfig {
|
||||||
|
return { type = ElementConfigType.Border, config = _StoreBorderElementConfig((BorderElementConfig){left = outsideBorders, right = outsideBorders, top = outsideBorders, bottom = outsideBorders}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderOutsideRadius :: proc(outsideBorders: BorderData, radius: f32) -> TypedConfig {
|
||||||
|
return { type = ElementConfigType.Border, config = _StoreBorderElementConfig(
|
||||||
|
(BorderElementConfig){left = outsideBorders, right = outsideBorders, top = outsideBorders, bottom = outsideBorders, cornerRadius = {radius, radius, radius, radius}},
|
||||||
|
) }
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderAll :: proc(allBorders: BorderData) -> TypedConfig {
|
||||||
|
return { type = ElementConfigType.Border, config = _StoreBorderElementConfig((BorderElementConfig){left = allBorders, right = allBorders, top = allBorders, bottom = allBorders, betweenChildren = allBorders}) }
|
||||||
|
}
|
||||||
|
|
||||||
|
BorderAllRadius :: proc(allBorders: BorderData, radius: f32) -> TypedConfig {
|
||||||
|
return { type = ElementConfigType.Border, config = _StoreBorderElementConfig(
|
||||||
|
(BorderElementConfig){left = allBorders, right = allBorders, top = allBorders, bottom = allBorders, cornerRadius = {radius, radius, radius, radius}},
|
||||||
|
) }
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> TypedConfig {
|
||||||
|
return { type = ElementConfigType.Id, id = _HashString(MakeString(label), index, 0) }
|
||||||
|
}
|
315
generator/generators/odin_generator.py
Normal file
315
generator/generators/odin_generator.py
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from parser import ExtractedSymbolType
|
||||||
|
from generators.base_generator import BaseGenerator
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def get_common_prefix(keys: list[str]) -> str:
|
||||||
|
# find a prefix that's shared between all keys
|
||||||
|
prefix = ""
|
||||||
|
for i in range(min(map(len, keys))):
|
||||||
|
if len(set(key[i] for key in keys)) > 1:
|
||||||
|
break
|
||||||
|
prefix += keys[0][i]
|
||||||
|
return prefix
|
||||||
|
|
||||||
|
def snake_case_to_pascal_case(snake_case: str) -> str:
|
||||||
|
return ''.join(word.lower().capitalize() for word in snake_case.split('_'))
|
||||||
|
|
||||||
|
|
||||||
|
SYMBOL_NAME_OVERRIDES = {
|
||||||
|
'Clay_TextElementConfigWrapMode': 'TextWrapMode',
|
||||||
|
'Clay_Border': 'BorderData',
|
||||||
|
'Clay_SizingMinMax': 'SizingConstraintsMinMax',
|
||||||
|
}
|
||||||
|
SYMBOL_COMPLETE_OVERRIDES = {
|
||||||
|
'Clay_RenderCommandArray': 'ClayArray(RenderCommand)',
|
||||||
|
'Clay_Context': 'Context',
|
||||||
|
'Clay_ElementConfig': None,
|
||||||
|
# 'Clay_SetQueryScrollOffsetFunction': None,
|
||||||
|
}
|
||||||
|
|
||||||
|
# These enums should have output binding members that are PascalCase instead of UPPER_SNAKE_CASE.
|
||||||
|
ENUM_MEMBER_PASCAL = {
|
||||||
|
'Clay_RenderCommandType',
|
||||||
|
'Clay_TextElementConfigWrapMode',
|
||||||
|
'Clay__ElementConfigType',
|
||||||
|
}
|
||||||
|
ENUM_MEMBER_OVERRIDES = {
|
||||||
|
'Clay__ElementConfigType': {
|
||||||
|
'CLAY__ELEMENT_CONFIG_TYPE_BORDER_CONTAINER': 'Border',
|
||||||
|
'CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER': 'Floating',
|
||||||
|
'CLAY__ELEMENT_CONFIG_TYPE_SCROLL_CONTAINER': 'Scroll',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ENUM_ADDITIONAL_MEMBERS = {
|
||||||
|
'Clay__ElementConfigType': {
|
||||||
|
'Id': 65,
|
||||||
|
'Layout': 66,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPE_MAPPING = {
|
||||||
|
'*char': '[^]c.char',
|
||||||
|
'const *char': '[^]c.char',
|
||||||
|
'*void': 'rawptr',
|
||||||
|
'bool': 'bool',
|
||||||
|
'float': 'c.float',
|
||||||
|
'uint16_t': 'u16',
|
||||||
|
'uint32_t': 'u32',
|
||||||
|
'int32_t': 'c.int32_t',
|
||||||
|
'uintptr_t': 'rawptr',
|
||||||
|
'intptr_t': 'rawptr',
|
||||||
|
'void': 'void',
|
||||||
|
}
|
||||||
|
STRUCT_TYPE_OVERRIDES = {
|
||||||
|
'Clay_Arena': {
|
||||||
|
'nextAllocation': 'uintptr',
|
||||||
|
'capacity': 'uintptr',
|
||||||
|
},
|
||||||
|
'Clay_SizingAxis': {
|
||||||
|
'size': 'SizingConstraints',
|
||||||
|
},
|
||||||
|
"Clay_RenderCommand": {
|
||||||
|
"zIndex": 'i32',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
STRUCT_MEMBER_OVERRIDES = {
|
||||||
|
'Clay_ErrorHandler': {
|
||||||
|
'errorHandlerFunction': 'handler',
|
||||||
|
},
|
||||||
|
'Clay_SizingAxis': {
|
||||||
|
'size': 'constraints',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
STRUCT_OVERRIDE_AS_FIXED_ARRAY = {
|
||||||
|
'Clay_Color',
|
||||||
|
'Clay_Vector2',
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION_PARAM_OVERRIDES = {
|
||||||
|
'Clay_SetCurrentContext': {
|
||||||
|
'context': 'ctx',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
FUNCTION_TYPE_OVERRIDES = {
|
||||||
|
'Clay_CreateArenaWithCapacityAndMemory': {
|
||||||
|
'offset': '[^]u8',
|
||||||
|
},
|
||||||
|
'Clay_SetMeasureTextFunction': {
|
||||||
|
'userData': 'uintptr',
|
||||||
|
},
|
||||||
|
'Clay_RenderCommandArray_Get': {
|
||||||
|
'index': 'i32',
|
||||||
|
},
|
||||||
|
"Clay__AttachElementConfig": {
|
||||||
|
"config": 'rawptr',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
class OdinGenerator(BaseGenerator):
|
||||||
|
|
||||||
|
def generate(self) -> None:
|
||||||
|
self.generate_structs()
|
||||||
|
self.generate_enums()
|
||||||
|
self.generate_functions()
|
||||||
|
|
||||||
|
odin_template_path = Path(__file__).parent / 'odin' / 'clay.template.odin'
|
||||||
|
with open(odin_template_path, 'r') as f:
|
||||||
|
template = f.read()
|
||||||
|
self.output_content['clay.odin'] = (
|
||||||
|
template
|
||||||
|
.replace('{{structs}}', '\n'.join(self.output_content['struct']))
|
||||||
|
.replace('{{enums}}', '\n'.join(self.output_content['enum']))
|
||||||
|
.replace('{{public_functions}}', '\n'.join(self.output_content['public_function']))
|
||||||
|
.replace('{{private_functions}}', '\n'.join(self.output_content['private_function']))
|
||||||
|
.splitlines()
|
||||||
|
)
|
||||||
|
del self.output_content['struct']
|
||||||
|
del self.output_content['enum']
|
||||||
|
del self.output_content['private_function']
|
||||||
|
del self.output_content['public_function']
|
||||||
|
|
||||||
|
def get_symbol_name(self, symbol: str) -> str:
|
||||||
|
if symbol in SYMBOL_NAME_OVERRIDES:
|
||||||
|
return SYMBOL_NAME_OVERRIDES[symbol]
|
||||||
|
symbol_type = self.get_symbol_type(symbol)
|
||||||
|
base_name = symbol.removeprefix('Clay_')
|
||||||
|
if symbol_type == 'enum':
|
||||||
|
return base_name.removeprefix('_') # Clay_ and Clay__ are exported as public types.
|
||||||
|
elif symbol_type == 'struct':
|
||||||
|
return base_name
|
||||||
|
elif symbol_type == 'function':
|
||||||
|
return base_name
|
||||||
|
raise ValueError(f'Unknown symbol: {symbol}')
|
||||||
|
|
||||||
|
def format_type(self, type: ExtractedSymbolType) -> str:
|
||||||
|
if isinstance(type, str):
|
||||||
|
return type
|
||||||
|
|
||||||
|
parameter_strs = []
|
||||||
|
for param_name, param_type in type['params']:
|
||||||
|
parameter_strs.append(f"{param_name}: {self.format_type(param_type or 'unknown')}")
|
||||||
|
return_type_str = ''
|
||||||
|
if type['return_type'] is not None and type['return_type'] != 'void':
|
||||||
|
return_type_str = ' -> ' + self.format_type(type['return_type'])
|
||||||
|
return f"proc \"c\" ({', '.join(parameter_strs)}){return_type_str}"
|
||||||
|
|
||||||
|
def resolve_binding_type(self, symbol: str, member: str | None, member_type: ExtractedSymbolType | None, type_overrides: dict[str, dict[str, str]]) -> str | None:
|
||||||
|
if isinstance(member_type, str):
|
||||||
|
if member_type in SYMBOL_COMPLETE_OVERRIDES:
|
||||||
|
return SYMBOL_COMPLETE_OVERRIDES[member_type]
|
||||||
|
if symbol in type_overrides and member in type_overrides[symbol]:
|
||||||
|
return type_overrides[symbol][member]
|
||||||
|
if member_type in TYPE_MAPPING:
|
||||||
|
return TYPE_MAPPING[member_type]
|
||||||
|
if member_type and self.has_symbol(member_type):
|
||||||
|
return self.get_symbol_name(member_type)
|
||||||
|
if member_type and member_type.startswith('*'):
|
||||||
|
result = self.resolve_binding_type(symbol, member, member_type[1:], type_overrides)
|
||||||
|
if result:
|
||||||
|
return f"^{result}"
|
||||||
|
return None
|
||||||
|
if member_type is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
resolved_parameters = []
|
||||||
|
for param_name, param_type in member_type['params']:
|
||||||
|
resolved_param = self.resolve_binding_type(symbol, param_name, param_type, type_overrides)
|
||||||
|
if resolved_param is None:
|
||||||
|
return None
|
||||||
|
resolved_parameters.append((param_name, resolved_param))
|
||||||
|
resolved_return_type = self.resolve_binding_type(symbol, None, member_type['return_type'], type_overrides)
|
||||||
|
if resolved_return_type is None:
|
||||||
|
return None
|
||||||
|
return self.format_type({
|
||||||
|
"params": resolved_parameters,
|
||||||
|
"return_type": resolved_return_type,
|
||||||
|
})
|
||||||
|
|
||||||
|
def generate_structs(self) -> None:
|
||||||
|
for struct, struct_data in sorted(self.extracted_symbols.structs.items(), key=lambda x: x[0]):
|
||||||
|
members = struct_data['attrs']
|
||||||
|
if not struct.startswith('Clay_'):
|
||||||
|
continue
|
||||||
|
if struct in SYMBOL_COMPLETE_OVERRIDES:
|
||||||
|
continue
|
||||||
|
|
||||||
|
binding_name = self.get_symbol_name(struct)
|
||||||
|
if binding_name.startswith('_'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if struct in STRUCT_OVERRIDE_AS_FIXED_ARRAY:
|
||||||
|
array_size = len(members)
|
||||||
|
first_elem = list(members.values())[0]
|
||||||
|
array_type = None
|
||||||
|
if 'type' in first_elem:
|
||||||
|
array_type = first_elem['type']
|
||||||
|
|
||||||
|
if array_type in TYPE_MAPPING:
|
||||||
|
array_binding_type = TYPE_MAPPING[array_type]
|
||||||
|
elif array_type and self.has_symbol(self.format_type(array_type)):
|
||||||
|
array_binding_type = self.get_symbol_name(self.format_type(array_type))
|
||||||
|
else:
|
||||||
|
self._write('struct', f"// {struct} ({array_type}) - has no mapping")
|
||||||
|
continue
|
||||||
|
|
||||||
|
self._write('struct', f"// {struct} (overridden as fixed array)")
|
||||||
|
self._write('struct', f"{binding_name} :: [{array_size}]{array_binding_type}")
|
||||||
|
self._write('struct', "")
|
||||||
|
continue
|
||||||
|
|
||||||
|
raw_union = ' #raw_union' if struct_data.get('is_union', False) else ''
|
||||||
|
|
||||||
|
self._write('struct', f"// {struct}")
|
||||||
|
self._write('struct', f"{binding_name} :: struct{raw_union} {{")
|
||||||
|
|
||||||
|
for member, member_info in members.items():
|
||||||
|
if struct in STRUCT_TYPE_OVERRIDES and member in STRUCT_TYPE_OVERRIDES[struct]:
|
||||||
|
member_type = 'unknown'
|
||||||
|
elif not 'type' in member_info:
|
||||||
|
self._write('struct', f" // {member} (unknown type)")
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
member_type = member_info['type']
|
||||||
|
|
||||||
|
binding_member_name = member
|
||||||
|
if struct in STRUCT_MEMBER_OVERRIDES and member in STRUCT_MEMBER_OVERRIDES[struct]:
|
||||||
|
binding_member_name = STRUCT_MEMBER_OVERRIDES[struct][member]
|
||||||
|
|
||||||
|
member_binding_type = self.resolve_binding_type(struct, member, member_type, STRUCT_TYPE_OVERRIDES)
|
||||||
|
if member_binding_type is None:
|
||||||
|
self._write('struct', f" // {binding_member_name} ({member_type}) - has no mapping")
|
||||||
|
continue
|
||||||
|
self._write('struct', f" {binding_member_name}: {member_binding_type}, // {member} ({member_type})")
|
||||||
|
self._write('struct', "}")
|
||||||
|
self._write('struct', '')
|
||||||
|
|
||||||
|
def generate_enums(self) -> None:
|
||||||
|
for enum, members in sorted(self.extracted_symbols.enums.items(), key=lambda x: x[0]):
|
||||||
|
if not enum.startswith('Clay_'):
|
||||||
|
continue
|
||||||
|
if enum in SYMBOL_COMPLETE_OVERRIDES:
|
||||||
|
continue
|
||||||
|
|
||||||
|
binding_name = self.get_symbol_name(enum)
|
||||||
|
common_member_prefix = get_common_prefix(list(members.keys()))
|
||||||
|
self._write('enum', f"// {enum}")
|
||||||
|
self._write('enum', f"{binding_name} :: enum EnumBackingType {{")
|
||||||
|
for member in members:
|
||||||
|
if enum in ENUM_MEMBER_OVERRIDES and member in ENUM_MEMBER_OVERRIDES[enum]:
|
||||||
|
binding_member_name = ENUM_MEMBER_OVERRIDES[enum][member]
|
||||||
|
else:
|
||||||
|
binding_member_name = member.removeprefix(common_member_prefix)
|
||||||
|
if enum in ENUM_MEMBER_PASCAL:
|
||||||
|
binding_member_name = snake_case_to_pascal_case(binding_member_name)
|
||||||
|
|
||||||
|
if members[member] is not None:
|
||||||
|
self._write('enum', f" {binding_member_name} = {members[member]}, // {member}")
|
||||||
|
else:
|
||||||
|
self._write('enum', f" {binding_member_name}, // {member}")
|
||||||
|
|
||||||
|
if enum in ENUM_ADDITIONAL_MEMBERS:
|
||||||
|
self._write('enum', ' // Odin specific enum types')
|
||||||
|
for member, value in ENUM_ADDITIONAL_MEMBERS[enum].items():
|
||||||
|
self._write('enum', f" {member} = {value},")
|
||||||
|
self._write('enum', "}")
|
||||||
|
self._write('enum', '')
|
||||||
|
|
||||||
|
def generate_functions(self) -> None:
|
||||||
|
for function, function_info in sorted(self.extracted_symbols.functions.items(), key=lambda x: x[0]):
|
||||||
|
if not function.startswith('Clay_'):
|
||||||
|
continue
|
||||||
|
if function in SYMBOL_COMPLETE_OVERRIDES:
|
||||||
|
continue
|
||||||
|
is_private = function.startswith('Clay__')
|
||||||
|
write_to = 'private_function' if is_private else 'public_function'
|
||||||
|
|
||||||
|
binding_name = self.get_symbol_name(function)
|
||||||
|
|
||||||
|
return_type = function_info['return_type']
|
||||||
|
binding_return_type = self.resolve_binding_type(function, None, return_type, {})
|
||||||
|
if binding_return_type is None:
|
||||||
|
self._write(write_to, f" // {function} ({return_type}) - has no mapping")
|
||||||
|
continue
|
||||||
|
|
||||||
|
skip = False
|
||||||
|
binding_params = []
|
||||||
|
for param_name, param_type in function_info['params']:
|
||||||
|
binding_param_name = param_name
|
||||||
|
if function in FUNCTION_PARAM_OVERRIDES and param_name in FUNCTION_PARAM_OVERRIDES[function]:
|
||||||
|
binding_param_name = FUNCTION_PARAM_OVERRIDES[function][param_name]
|
||||||
|
binding_param_type = self.resolve_binding_type(function, param_name, param_type, FUNCTION_TYPE_OVERRIDES)
|
||||||
|
if binding_param_type is None:
|
||||||
|
skip = True
|
||||||
|
binding_params.append(f"{binding_param_name}: {binding_param_type}")
|
||||||
|
if skip:
|
||||||
|
self._write(write_to, f" // {function} - has no mapping")
|
||||||
|
continue
|
||||||
|
|
||||||
|
binding_params_str = ', '.join(binding_params)
|
||||||
|
return_str = f" -> {binding_return_type}" if binding_return_type != 'void' else ''
|
||||||
|
self._write(write_to, f" {binding_name} :: proc({binding_params_str}){return_str} --- // {function}")
|
||||||
|
|
173
generator/parser.py
Normal file
173
generator/parser.py
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional, TypedDict, NotRequired, Union
|
||||||
|
from pycparser import c_ast, parse_file, preprocess_file
|
||||||
|
from pathlib import Path
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
ExtractedSymbolType = Union[str, "ExtractedFunction"]
|
||||||
|
|
||||||
|
class ExtractedStructAttributeUnion(TypedDict):
|
||||||
|
type: Optional[ExtractedSymbolType]
|
||||||
|
|
||||||
|
class ExtractedStructAttribute(TypedDict):
|
||||||
|
type: NotRequired[ExtractedSymbolType]
|
||||||
|
union: NotRequired[dict[str, Optional[ExtractedSymbolType]]]
|
||||||
|
|
||||||
|
class ExtractedStruct(TypedDict):
|
||||||
|
attrs: dict[str, ExtractedStructAttribute]
|
||||||
|
is_union: NotRequired[bool]
|
||||||
|
|
||||||
|
ExtractedEnum = dict[str, Optional[str]]
|
||||||
|
ExtractedFunctionParam = tuple[str, Optional[ExtractedSymbolType]]
|
||||||
|
|
||||||
|
class ExtractedFunction(TypedDict):
|
||||||
|
return_type: Optional["ExtractedSymbolType"]
|
||||||
|
params: list[ExtractedFunctionParam]
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ExtractedSymbols:
|
||||||
|
structs: dict[str, ExtractedStruct]
|
||||||
|
enums: dict[str, ExtractedEnum]
|
||||||
|
functions: dict[str, ExtractedFunction]
|
||||||
|
|
||||||
|
def get_type_names(node: c_ast.Node, prefix: str="") -> Optional[ExtractedSymbolType]:
|
||||||
|
if isinstance(node, c_ast.TypeDecl) and hasattr(node, 'quals') and node.quals:
|
||||||
|
prefix = " ".join(node.quals) + " " + prefix
|
||||||
|
if isinstance(node, c_ast.PtrDecl):
|
||||||
|
prefix = "*" + prefix
|
||||||
|
if isinstance(node, c_ast.FuncDecl):
|
||||||
|
func: ExtractedFunction = {
|
||||||
|
'return_type': get_type_names(node.type),
|
||||||
|
'params': [],
|
||||||
|
}
|
||||||
|
for param in node.args.params:
|
||||||
|
if param.name is None:
|
||||||
|
continue
|
||||||
|
func['params'].append((param.name, get_type_names(param)))
|
||||||
|
return func
|
||||||
|
|
||||||
|
if hasattr(node, 'names'):
|
||||||
|
return prefix + node.names[0] # type: ignore
|
||||||
|
elif hasattr(node, 'type'):
|
||||||
|
return get_type_names(node.type, prefix) # type: ignore
|
||||||
|
return None
|
||||||
|
|
||||||
|
class Visitor(c_ast.NodeVisitor):
|
||||||
|
def __init__(self):
|
||||||
|
self.structs: dict[str, ExtractedStruct] = {}
|
||||||
|
self.enums: dict[str, ExtractedEnum] = {}
|
||||||
|
self.functions: dict[str, ExtractedFunction] = {}
|
||||||
|
|
||||||
|
def visit_FuncDecl(self, node: c_ast.FuncDecl):
|
||||||
|
# node.show()
|
||||||
|
# logger.debug(node)
|
||||||
|
node_type = node.type
|
||||||
|
is_pointer = False
|
||||||
|
if isinstance(node.type, c_ast.PtrDecl):
|
||||||
|
node_type = node.type.type
|
||||||
|
is_pointer = True
|
||||||
|
|
||||||
|
if hasattr(node_type, "declname"):
|
||||||
|
return_type = get_type_names(node_type.type)
|
||||||
|
if return_type is not None and isinstance(return_type, str) and is_pointer:
|
||||||
|
return_type = "*" + return_type
|
||||||
|
func: ExtractedFunction = {
|
||||||
|
'return_type': return_type,
|
||||||
|
'params': [],
|
||||||
|
}
|
||||||
|
for param in node.args.params:
|
||||||
|
if param.name is None:
|
||||||
|
continue
|
||||||
|
func['params'].append((param.name, get_type_names(param)))
|
||||||
|
self.functions[node_type.declname] = func
|
||||||
|
self.generic_visit(node)
|
||||||
|
|
||||||
|
def visit_Struct(self, node: c_ast.Struct):
|
||||||
|
# node.show()
|
||||||
|
if node.name and node.decls:
|
||||||
|
struct = {}
|
||||||
|
for decl in node.decls:
|
||||||
|
struct[decl.name] = {
|
||||||
|
"type": get_type_names(decl),
|
||||||
|
}
|
||||||
|
self.structs[node.name] = {
|
||||||
|
'attrs': struct,
|
||||||
|
}
|
||||||
|
self.generic_visit(node)
|
||||||
|
|
||||||
|
def visit_Typedef(self, node: c_ast.Typedef):
|
||||||
|
# node.show()
|
||||||
|
if hasattr(node.type, 'type') and hasattr(node.type.type, 'decls') and node.type.type.decls:
|
||||||
|
struct = {}
|
||||||
|
for decl in node.type.type.decls:
|
||||||
|
if hasattr(decl, 'type') and hasattr(decl.type, 'type') and isinstance(decl.type.type, c_ast.Union):
|
||||||
|
union = {}
|
||||||
|
for field in decl.type.type.decls:
|
||||||
|
union[field.name] = get_type_names(field)
|
||||||
|
struct[decl.name] = {
|
||||||
|
'union': union
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
struct[decl.name] = {
|
||||||
|
"type": get_type_names(decl),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.structs[node.name] = {
|
||||||
|
'attrs': struct,
|
||||||
|
'is_union': isinstance(node.type.type, c_ast.Union),
|
||||||
|
}
|
||||||
|
if hasattr(node.type, 'type') and isinstance(node.type.type, c_ast.Enum):
|
||||||
|
enum = {}
|
||||||
|
for enumerator in node.type.type.values.enumerators:
|
||||||
|
if enumerator.value is None:
|
||||||
|
enum[enumerator.name] = None
|
||||||
|
else:
|
||||||
|
enum[enumerator.name] = enumerator.value.value
|
||||||
|
self.enums[node.name] = enum
|
||||||
|
self.generic_visit(node)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_headers(input_files: list[Path], tmp_dir: Path) -> ExtractedSymbols:
|
||||||
|
cpp_args = ["-nostdinc", "-D__attribute__(x)=", "-E"]
|
||||||
|
|
||||||
|
# Make a new clay.h that combines the provided input files, so that we can add bindings for customized structs
|
||||||
|
with open(tmp_dir / 'merged_clay.h', 'w') as f:
|
||||||
|
for input_file in input_files:
|
||||||
|
with open(input_file, 'r') as f2:
|
||||||
|
for line in f2:
|
||||||
|
# Ignore includes, as they should be manually included in input_files.
|
||||||
|
if line.startswith("#include"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Ignore the CLAY_IMPLEMENTATION define, because we only want to parse the public api code.
|
||||||
|
# This is helpful so that the user can provide their implementation code, which will contain any custom extensions
|
||||||
|
if "#define CLAY_IMPLEMENTATION" in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
f.write(line)
|
||||||
|
|
||||||
|
# Preprocess the file
|
||||||
|
logger.info("Preprocessing file")
|
||||||
|
preprocessed = preprocess_file(tmp_dir / 'merged_clay.h', cpp_path="cpp", cpp_args=cpp_args) # type: ignore
|
||||||
|
with open(tmp_dir / 'clay.preprocessed.h', 'w') as f:
|
||||||
|
f.write(preprocessed)
|
||||||
|
|
||||||
|
# Parse the file
|
||||||
|
logger.info("Parsing file")
|
||||||
|
ast = parse_file(tmp_dir / 'clay.preprocessed.h', use_cpp=False) # type: ignore
|
||||||
|
|
||||||
|
# Extract symbols
|
||||||
|
visitor = Visitor()
|
||||||
|
visitor.visit(ast)
|
||||||
|
|
||||||
|
result = ExtractedSymbols(
|
||||||
|
structs=visitor.structs,
|
||||||
|
enums=visitor.enums,
|
||||||
|
functions=visitor.functions
|
||||||
|
)
|
||||||
|
return result
|
1
generator/requirements.txt
Normal file
1
generator/requirements.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
pycparser==2.22
|
Loading…
Reference in New Issue
Block a user