diff --git a/bindings/odin/clay-odin/clay.odin b/bindings/odin/clay-odin/clay.odin index badeea7..6cf7fef 100644 --- a/bindings/odin/clay-odin/clay.odin +++ b/bindings/odin/clay-odin/clay.odin @@ -18,14 +18,14 @@ when ODIN_OS == .Windows { String :: struct { isStaticallyAllocated: c.bool, - length: c.int32_t, - chars: [^]c.char, + length: c.int32_t, + chars: [^]c.char, } StringSlice :: struct { - length: c.int32_t, - chars: [^]c.char, - baseChars: [^]c.char, + length: c.int32_t, + chars: [^]c.char, + baseChars: [^]c.char, } Vector2 :: [2]c.float @@ -57,11 +57,6 @@ CornerRadius :: struct { bottomRight: c.float, } -BorderData :: struct { - width: u32, - color: Color, -} - ElementId :: struct { id: u32, offset: u32, @@ -69,6 +64,12 @@ ElementId :: struct { stringId: String, } +ElementIdArray :: struct { + capacity: i32, + length: i32, + internalArray: [^]ElementId, +} + when ODIN_OS == .Windows { EnumBackingType :: u32 } else { @@ -83,11 +84,13 @@ RenderCommandType :: enum EnumBackingType { Image, ScissorStart, ScissorEnd, + OverlayColorStart, + OverlayColorEnd, Custom, } RectangleElementConfig :: struct { - color: Color, + color: Color, } TextWrapMode :: enum EnumBackingType { @@ -103,22 +106,22 @@ TextAlignment :: enum EnumBackingType { } TextElementConfig :: struct { - userData: rawptr, - textColor: Color, - fontId: u16, - fontSize: u16, - letterSpacing: u16, - lineHeight: u16, - wrapMode: TextWrapMode, - textAlignment: TextAlignment, + userData: rawptr, + textColor: Color, + fontId: u16, + fontSize: u16, + letterSpacing: u16, + lineHeight: u16, + wrapMode: TextWrapMode, + textAlignment: TextAlignment, } AspectRatioElementConfig :: struct { - aspectRatio: f32, + aspectRatio: f32, } ImageElementConfig :: struct { - imageData: rawptr, + imageData: rawptr, } CustomElementConfig :: struct { @@ -126,10 +129,10 @@ CustomElementConfig :: struct { } BorderWidth :: struct { - left: u16, - right: u16, - top: u16, - bottom: u16, + left: u16, + right: u16, + top: u16, + bottom: u16, betweenChildren: u16, } @@ -138,6 +141,87 @@ BorderElementConfig :: struct { width: BorderWidth, } +TransitionData :: struct { + boundingBox: BoundingBox, + backgroundColor: Color, + overlayColor: Color, + borderColor: Color, + borderWidth: BorderWidth, +} + +TransitionState :: enum c.int { + Idle, + Entering, + Transitioning, + Exiting, +} + +TransitionProperty :: enum c.int { + None, + X, + Y, + Width, + Height, + BackgroundColor, + OverlayColor, + CornerRadius, + BorderColor, + BorderWidth, +} + +TransitionPropertyFlags :: bit_set[TransitionProperty;c.int] +TransitionPropertyPosition :: TransitionPropertyFlags{.X, .Y} +TransitionPropertyDimensions :: TransitionPropertyFlags{.Width, .Height} +TransitionPropertyBoundingBox :: TransitionPropertyPosition + TransitionPropertyDimensions +TransitionPropertyBorder :: TransitionPropertyFlags{.BorderColor, .BorderWidth} + +TransitionCallbackArguments :: struct { + transitionState: TransitionState, + initial: TransitionData, + current: ^TransitionData, + target: TransitionData, + elapsedTime: f32, + duration: f32, + properties: TransitionPropertyFlags, +} + +TransitionEnterTriggerType :: enum EnumBackingType { + SkipOnFirstParentFrame, + TriggerOnFirstParentFrame, +} + +TransitionExitTriggerType :: enum EnumBackingType { + SkipWhenParentExits, + TriggerWhenParentExits, +} + +TransitionInteractionHandlingType :: enum EnumBackingType { + DisableInteractionsWhileTransitioningPosition, + AllowInteractionsWhileTransitioningPosition, +} + +ExitTransitionSiblingOrdering :: enum EnumBackingType { + UnderneathSiblings, + NaturalOrder, + AboveSiblings, +} + +TransitionElementConfig :: struct { + handler: proc "c" (args: TransitionCallbackArguments) -> bool, + duration: f32, + properties: TransitionPropertyFlags, + interactionHandling: TransitionInteractionHandlingType, + enter: struct { + setInitialState: proc "c" (initialState: TransitionData, properties: TransitionPropertyFlags) -> TransitionData, + trigger: TransitionEnterTriggerType, + }, + exit: struct { + setFinalState: proc "c" (finalState: TransitionData, properties: TransitionPropertyFlags) -> TransitionData, + trigger: TransitionExitTriggerType, + siblingOrdering: ExitTransitionSiblingOrdering, + }, +} + ClipElementConfig :: struct { horizontal: bool, // clip overflowing elements on the "X" axis vertical: bool, // clip overflowing elements on the "Y" axis @@ -191,51 +275,62 @@ FloatingElementConfig :: struct { TextRenderData :: struct { stringContents: StringSlice, - textColor: Color, - fontId: u16, - fontSize: u16, - letterSpacing: u16, - lineHeight: u16, + textColor: Color, + fontId: u16, + fontSize: u16, + letterSpacing: u16, + lineHeight: u16, } RectangleRenderData :: struct { backgroundColor: Color, - cornerRadius: CornerRadius, + cornerRadius: CornerRadius, } ImageRenderData :: struct { backgroundColor: Color, - cornerRadius: CornerRadius, - imageData: rawptr, + cornerRadius: CornerRadius, + imageData: rawptr, } CustomRenderData :: struct { backgroundColor: Color, - cornerRadius: CornerRadius, - customData: rawptr, + cornerRadius: CornerRadius, + customData: rawptr, +} + +ClipRenderData :: struct { + horizontal: bool, + vertical: bool, +} + +OverlayColorRenderData :: struct { + color: Color, } BorderRenderData :: struct { - color: Color, + color: Color, cornerRadius: CornerRadius, - width: BorderWidth, + width: BorderWidth, } RenderCommandData :: struct #raw_union { - rectangle: RectangleRenderData, - text: TextRenderData, - image: ImageRenderData, - custom: CustomRenderData, - border: BorderRenderData, + rectangle: RectangleRenderData, + text: TextRenderData, + image: ImageRenderData, + custom: CustomRenderData, + border: BorderRenderData, + clip: ClipRenderData, + overlayColor: OverlayColorRenderData, } RenderCommand :: struct { - boundingBox: BoundingBox, - renderData: RenderCommandData, - userData: rawptr, - id: u32, - zIndex: i16, - commandType: RenderCommandType, + boundingBox: BoundingBox, + renderData: RenderCommandData, + userData: rawptr, + id: u32, + zIndex: i16, + commandType: RenderCommandType, } ScrollContainerData :: struct { @@ -295,9 +390,9 @@ Sizing :: struct { } Padding :: struct { - left: u16, - right: u16, - top: u16, + left: u16, + right: u16, + top: u16, bottom: u16, } @@ -340,6 +435,7 @@ ClayArray :: struct($type: typeid) { ElementDeclaration :: struct { layout: LayoutConfig, backgroundColor: Color, + overlayColor: Color, cornerRadius: CornerRadius, aspectRatio: AspectRatioElementConfig, image: ImageElementConfig, @@ -347,6 +443,7 @@ ElementDeclaration :: struct { custom: CustomElementConfig, clip: ClipElementConfig, border: BorderElementConfig, + transition: TransitionElementConfig, userData: rawptr, } @@ -359,16 +456,17 @@ ErrorType :: enum EnumBackingType { FloatingContainerParentNotFound, PercentageOver1, InternalError, + UnbalancedOpenClose, } ErrorData :: struct { errorType: ErrorType, errorText: String, - userData: rawptr, + userData: rawptr, } ErrorHandler :: struct { - handler: proc "c" (errorData: ErrorData), + handler: proc "c" (errorData: ErrorData), userData: rawptr, } @@ -382,19 +480,22 @@ foreign Clay { MinMemorySize :: proc() -> u32 --- CreateArenaWithCapacityAndMemory :: proc(capacity: c.size_t, offset: [^]u8) -> Arena --- SetPointerState :: proc(position: Vector2, pointerDown: bool) --- + GetPointerState :: proc() -> PointerData --- Initialize :: proc(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) -> ^Context --- GetCurrentContext :: proc() -> ^Context --- SetCurrentContext :: proc(ctx: ^Context) --- UpdateScrollContainers :: proc(enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: c.float) --- SetLayoutDimensions :: proc(dimensions: Dimensions) --- BeginLayout :: proc() --- - EndLayout :: proc() -> ClayArray(RenderCommand) --- + EndLayout :: proc(deltaTime: c.float) -> ClayArray(RenderCommand) --- + GetOpenElementId :: proc() -> u32 --- GetElementId :: proc(id: String) -> ElementId --- GetElementIdWithIndex :: proc(id: String, index: u32) -> ElementId --- GetElementData :: proc(id: ElementId) -> ElementData --- Hovered :: proc() -> bool --- OnHover :: proc(onHoverFunction: proc "c" (id: ElementId, pointerData: PointerData, userData: rawptr), userData: rawptr) --- PointerOver :: proc(id: ElementId) -> bool --- + GetPointerOverIds :: proc() -> ElementIdArray --- GetScrollOffset :: proc() -> Vector2 --- GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData --- SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: StringSlice, config: ^TextElementConfig, userData: rawptr) -> Dimensions, userData: rawptr) --- @@ -408,6 +509,7 @@ foreign Clay { GetMaxMeasureTextCacheWordCount :: proc() -> i32 --- SetMaxMeasureTextCacheWordCount :: proc(maxMeasureTextCacheWordCount: i32) --- ResetMeasureTextCache :: proc() --- + EaseOut :: proc(arguments: TransitionCallbackArguments) -> bool --- } @(link_prefix = "Clay_", default_calling_convention = "c", private) @@ -415,9 +517,7 @@ foreign Clay { _ConfigureOpenElement :: proc(config: ElementDeclaration) --- _HashString :: proc(key: String, seed: u32) -> ElementId --- _HashStringWithOffset :: proc(key: String, index: u32, seed: u32) -> ElementId --- - _OpenTextElement :: proc(text: String, textConfig: ^TextElementConfig) --- - _StoreTextElementConfig :: proc(config: TextElementConfig) -> ^TextElementConfig --- - _GetParentElementId :: proc() -> u32 --- + _OpenTextElement :: proc(text: String, textConfig: TextElementConfig) --- } ConfigureOpenElement :: proc(config: ElementDeclaration) -> bool { @@ -426,35 +526,39 @@ ConfigureOpenElement :: proc(config: ElementDeclaration) -> bool { } @(deferred_none = _CloseElement) -UI_WithId :: proc(id: ElementId) -> proc (config: ElementDeclaration) -> bool { +UI_WithId :: proc(id: ElementId) -> proc(config: ElementDeclaration) -> bool { _OpenElementWithId(id) return ConfigureOpenElement } @(deferred_none = _CloseElement) -UI_AutoId :: proc() -> proc (config: ElementDeclaration) -> bool { +UI_AutoId :: proc() -> proc(config: ElementDeclaration) -> bool { _OpenElement() return ConfigureOpenElement } -UI :: proc{UI_WithId, UI_AutoId} +UI :: proc { + UI_WithId, + UI_AutoId, +} -Text :: proc($text: string, config: ^TextElementConfig) { +Text :: proc { + TextStatic, + TextDynamic, +} + +TextStatic :: proc($text: string, config: TextElementConfig) { wrapped := MakeString(text) wrapped.isStaticallyAllocated = true _OpenTextElement(wrapped, config) } -TextDynamic :: proc(text: string, config: ^TextElementConfig) { +TextDynamic :: proc(text: string, config: TextElementConfig) { _OpenTextElement(MakeString(text), config) } -TextConfig :: proc(config: TextElementConfig) -> ^TextElementConfig { - return _StoreTextElementConfig(config) -} - PaddingAll :: proc(allPadding: u16) -> Padding { - return { left = allPadding, right = allPadding, top = allPadding, bottom = allPadding } + return {left = allPadding, right = allPadding, top = allPadding, bottom = allPadding} } BorderOutside :: proc(width: u16) -> BorderWidth { @@ -494,5 +598,5 @@ ID :: proc(label: string, index: u32 = 0) -> ElementId { } ID_LOCAL :: proc(label: string, index: u32 = 0) -> ElementId { - return _HashStringWithOffset(MakeString(label), index, _GetParentElementId()) + return _HashStringWithOffset(MakeString(label), index, GetOpenElementId()) } diff --git a/bindings/odin/clay-odin/linux/clay.a b/bindings/odin/clay-odin/linux/clay.a index 1f37ab3..b4edcb7 100644 Binary files a/bindings/odin/clay-odin/linux/clay.a and b/bindings/odin/clay-odin/linux/clay.a differ diff --git a/bindings/odin/clay-odin/macos-arm64/clay.a b/bindings/odin/clay-odin/macos-arm64/clay.a index b446371..334a9f1 100644 Binary files a/bindings/odin/clay-odin/macos-arm64/clay.a and b/bindings/odin/clay-odin/macos-arm64/clay.a differ diff --git a/bindings/odin/clay-odin/macos/clay.a b/bindings/odin/clay-odin/macos/clay.a index 5fd5492..e2ffc0e 100644 Binary files a/bindings/odin/clay-odin/macos/clay.a and b/bindings/odin/clay-odin/macos/clay.a differ diff --git a/bindings/odin/clay-odin/wasm/clay.o b/bindings/odin/clay-odin/wasm/clay.o index 9dfd14b..f56a730 100644 Binary files a/bindings/odin/clay-odin/wasm/clay.o and b/bindings/odin/clay-odin/wasm/clay.o differ diff --git a/bindings/odin/clay-odin/windows/clay.lib b/bindings/odin/clay-odin/windows/clay.lib index 35cc2b9..a354aa8 100644 Binary files a/bindings/odin/clay-odin/windows/clay.lib and b/bindings/odin/clay-odin/windows/clay.lib differ diff --git a/bindings/odin/examples/clay-official-website/clay-official-website.odin b/bindings/odin/examples/clay-official-website/clay-official-website.odin index 78b4e28..5d779a4 100644 --- a/bindings/odin/examples/clay-official-website/clay-official-website.odin +++ b/bindings/odin/examples/clay-official-website/clay-official-website.odin @@ -2,7 +2,6 @@ package main import clay "../../clay-odin" import "core:c" -import "core:fmt" import "vendor:raylib" windowWidth: i32 = 1024 @@ -52,464 +51,443 @@ COLOR_BLOB_BORDER_4 :: clay.Color{236, 159, 70, 255} COLOR_BLOB_BORDER_5 :: clay.Color{240, 189, 100, 255} headerTextConfig := clay.TextElementConfig { - fontId = FONT_ID_BODY_24, - fontSize = 24, - textColor = {61, 26, 5, 255}, + fontId = FONT_ID_BODY_24, + fontSize = 24, + textColor = {61, 26, 5, 255}, } border2pxRed := clay.BorderElementConfig { - width = { 2, 2, 2, 2, 0 }, - color = COLOR_RED + width = {2, 2, 2, 2, 0}, + color = COLOR_RED, } LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, $text: string, image: ^raylib.Texture2D) { - if clay.UI(clay.ID("HeroBlob", index))({ - layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } }, - border = border2pxRed, - cornerRadius = clay.CornerRadiusAll(10) - }) { - if clay.UI(clay.ID("CheckImage", index))({ - layout = { sizing = { width = clay.SizingFixed(32) } }, - aspectRatio = { 1.0 }, - image = { imageData = image }, - }) {} - clay.Text(text, clay.TextConfig({fontSize = fontSize, fontId = fontId, textColor = color})) - } + if clay.UI(clay.ID("HeroBlob", index))( + { + layout = {sizing = {width = clay.SizingGrow({max = 480})}, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{y = .Center}}, + border = border2pxRed, + cornerRadius = clay.CornerRadiusAll(10), + }, + ) { + if clay.UI(clay.ID("CheckImage", index))({layout = {sizing = {width = clay.SizingFixed(32)}}, aspectRatio = {1.0}, image = {imageData = image}}) {} + clay.Text(text, {fontSize = fontSize, fontId = fontId, textColor = color}) + } } LandingPageDesktop :: proc() { - if clay.UI(clay.ID("LandingPage1Desktop"))({ - layout = { sizing = { width = clay.SizingGrow(), height = clay.SizingFit({ min = cast(f32)windowHeight - 70 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } }, - }) { - if clay.UI(clay.ID("LandingPage1"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingGrow() }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 }, - border = { COLOR_RED, { left = 2, right = 2 } }, - }) { - if clay.UI(clay.ID("LeftText"))({ layout = { sizing = { width = clay.SizingPercent(0.55) }, layoutDirection = .TopToBottom, childGap = 8 } }) { - clay.Text( - "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}), - ) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {} - clay.Text( - "Clay is laying out this webpage right now!", - clay.TextConfig({fontSize = 36, fontId = FONT_ID_TITLE_36, textColor = COLOR_ORANGE}), - ) - } - if clay.UI(clay.ID("HeroImageOuter"))({ - layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingPercent(0.45) }, childAlignment = { x = .Center }, childGap = 16 }, - }) { - LandingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, "High performance", &checkImage5) - LandingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, "Flexbox-style responsive layout", &checkImage4) - LandingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, "Declarative syntax", &checkImage3) - LandingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, "Single .h file for C/C++", &checkImage2) - LandingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, "Compile to 15kb .wasm", &checkImage1) - } - } - } + if clay.UI(clay.ID("LandingPage1Desktop"))( + { + layout = { + sizing = {width = clay.SizingGrow(), height = clay.SizingFit({min = cast(f32)windowHeight - 70})}, + childAlignment = {y = .Center}, + padding = {left = 50, right = 50}, + }, + }, + ) { + if clay.UI(clay.ID("LandingPage1"))( + { + layout = {sizing = {clay.SizingGrow(), clay.SizingGrow()}, childAlignment = {y = .Center}, padding = clay.PaddingAll(32), childGap = 32}, + border = {COLOR_RED, {left = 2, right = 2}}, + }, + ) { + if clay.UI(clay.ID("LeftText"))({layout = {sizing = {width = clay.SizingPercent(0.55)}, layoutDirection = .TopToBottom, childGap = 8}}) { + clay.Text( + "Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", + {fontSize = 56, fontId = FONT_ID_TITLE_56, textColor = COLOR_RED}, + ) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(32)}}}) {} + clay.Text("Clay is laying out this webpage right now!", {fontSize = 36, fontId = FONT_ID_TITLE_36, textColor = COLOR_ORANGE}) + } + if clay.UI(clay.ID("HeroImageOuter"))( + {layout = {layoutDirection = .TopToBottom, sizing = {width = clay.SizingPercent(0.45)}, childAlignment = {x = .Center}, childGap = 16}}, + ) { + LandingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, "High performance", &checkImage5) + LandingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, "Flexbox-style responsive layout", &checkImage4) + LandingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, "Declarative syntax", &checkImage3) + LandingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, "Single .h file for C/C++", &checkImage2) + LandingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, "Compile to 15kb .wasm", &checkImage1) + } + } + } } LandingPageMobile :: proc() { - if clay.UI(clay.ID("LandingPage1Mobile"))({ - layout = { - layoutDirection = .TopToBottom, - sizing = { width = clay.SizingGrow(), height = clay.SizingFit({ min = cast(f32)windowHeight - 70 }) }, - childAlignment = { x = .Center, y = .Center }, - padding = { 16, 16, 32, 32 }, - childGap = 32, - }, - }) { - if clay.UI(clay.ID("LeftText"))({ layout = { sizing = { width = clay.SizingGrow() }, layoutDirection = .TopToBottom, childGap = 8 } }) { - clay.Text( - "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}), - ) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({}), height = clay.SizingFixed(32) } } }) {} - clay.Text( - "Clay is laying out this webpage right now!", - clay.TextConfig({fontSize = 32, fontId = FONT_ID_TITLE_32, textColor = COLOR_ORANGE}), - ) - } - if clay.UI(clay.ID("HeroImageOuter"))({ - layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow() }, childAlignment = { x = .Center }, childGap = 16 }, - }) { - LandingPageBlob(1, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_5, "High performance", &checkImage5) - LandingPageBlob(2, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_4, "Flexbox-style responsive layout", &checkImage4) - LandingPageBlob(3, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_3, "Declarative syntax", &checkImage3) - LandingPageBlob(4, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_2, "Single .h file for C/C++", &checkImage2) - LandingPageBlob(5, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_1, "Compile to 15kb .wasm", &checkImage1) - } - } + if clay.UI(clay.ID("LandingPage1Mobile"))( + { + layout = { + layoutDirection = .TopToBottom, + sizing = {width = clay.SizingGrow(), height = clay.SizingFit({min = cast(f32)windowHeight - 70})}, + childAlignment = {x = .Center, y = .Center}, + padding = {16, 16, 32, 32}, + childGap = 32, + }, + }, + ) { + if clay.UI(clay.ID("LeftText"))({layout = {sizing = {width = clay.SizingGrow()}, layoutDirection = .TopToBottom, childGap = 8}}) { + clay.Text( + "Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", + {fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}, + ) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow({}), height = clay.SizingFixed(32)}}}) {} + clay.Text("Clay is laying out this webpage right now!", {fontSize = 32, fontId = FONT_ID_TITLE_32, textColor = COLOR_ORANGE}) + } + if clay.UI(clay.ID("HeroImageOuter"))({layout = {layoutDirection = .TopToBottom, sizing = {width = clay.SizingGrow()}, childAlignment = {x = .Center}, childGap = 16}}) { + LandingPageBlob(1, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_5, "High performance", &checkImage5) + LandingPageBlob(2, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_4, "Flexbox-style responsive layout", &checkImage4) + LandingPageBlob(3, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_3, "Declarative syntax", &checkImage3) + LandingPageBlob(4, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_2, "Single .h file for C/C++", &checkImage2) + LandingPageBlob(5, 24, FONT_ID_BODY_24, COLOR_BLOB_BORDER_1, "Compile to 15kb .wasm", &checkImage1) + } + } } FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) { - textConfig := clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_RED}) - if clay.UI(clay.ID("HFileBoxOuter"))({ - layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 }, - }) { - if clay.UI(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("~2000 lines of C99.", textConfig) - clay.Text("Zero dependencies, including no C standard library.", textConfig) - } - if clay.UI(clay.ID("BringYourOwnRendererOuter"))({ - layout = { layoutDirection = .TopToBottom, sizing = { width = widthSizing }, childAlignment = { y = .Center }, padding = { outerPadding, outerPadding, 32, 32 }, childGap = 8 }, - }) { - clay.Text("Renderer agnostic.", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = COLOR_ORANGE})) - clay.Text("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML.", textConfig) - clay.Text("Flexible output for easy compositing in your custom engine or environment.", textConfig) - } + textConfig := clay.TextElementConfig { + fontSize = 24, + fontId = FONT_ID_BODY_24, + textColor = COLOR_RED, + } + if clay.UI(clay.ID("HFileBoxOuter"))( + {layout = {layoutDirection = .TopToBottom, sizing = {width = widthSizing}, childAlignment = {y = .Center}, padding = {outerPadding, outerPadding, 32, 32}, childGap = 8}}, + ) { + if clay.UI(clay.ID("HFileIncludeOuter"))({layout = {padding = {8, 8, 4, 4}}, backgroundColor = COLOR_RED, cornerRadius = clay.CornerRadiusAll(8)}) { + clay.Text("#include clay.h", {fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_LIGHT}) + } + clay.Text("~2000 lines of C99.", textConfig) + clay.Text("Zero dependencies, including no C standard library.", textConfig) + } + if clay.UI(clay.ID("BringYourOwnRendererOuter"))( + {layout = {layoutDirection = .TopToBottom, sizing = {width = widthSizing}, childAlignment = {y = .Center}, padding = {outerPadding, outerPadding, 32, 32}, childGap = 8}}, + ) { + clay.Text("Renderer agnostic.", {fontId = FONT_ID_BODY_24, fontSize = 24, textColor = COLOR_ORANGE}) + clay.Text("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML.", textConfig) + clay.Text("Flexible output for easy compositing in your custom engine or environment.", textConfig) + } } FeatureBlocksDesktop :: proc() { - if clay.UI(clay.ID("FeatureBlocksOuter"))({ layout = { sizing = { width = clay.SizingGrow({}) } } }) { - if clay.UI(clay.ID("FeatureBlocksInner"))({ - layout = { sizing = { width = clay.SizingGrow() }, childAlignment = { y = .Center } }, - border = { width = { betweenChildren = 2}, color = COLOR_RED }, - }) { - FeatureBlocks(clay.SizingPercent(0.5), 50) - } - } + if clay.UI(clay.ID("FeatureBlocksOuter"))({layout = {sizing = {width = clay.SizingGrow({})}}}) { + if clay.UI(clay.ID("FeatureBlocksInner"))( + {layout = {sizing = {width = clay.SizingGrow()}, childAlignment = {y = .Center}}, border = {width = {betweenChildren = 2}, color = COLOR_RED}}, + ) { + FeatureBlocks(clay.SizingPercent(0.5), 50) + } + } } FeatureBlocksMobile :: proc() { - if clay.UI(clay.ID("FeatureBlocksInner"))({ - layout = { layoutDirection = .TopToBottom, sizing = { width = clay.SizingGrow() } }, - border = { width = { betweenChildren = 2}, color = COLOR_RED }, - }) { - FeatureBlocks(clay.SizingGrow({}), 16) - } + if clay.UI(clay.ID("FeatureBlocksInner"))( + {layout = {layoutDirection = .TopToBottom, sizing = {width = clay.SizingGrow()}}, border = {width = {betweenChildren = 2}, color = COLOR_RED}}, + ) { + FeatureBlocks(clay.SizingGrow({}), 16) + } } DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) { - if clay.UI(clay.ID("SyntaxPageLeftText"))({ layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) { - clay.Text("Declarative Syntax", clay.TextConfig(titleTextConfig)) - if clay.UI(clay.ID("SyntaxSpacer"))({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {} - clay.Text( - "Flexible and readable declarative syntax with nested UI element hierarchies.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}), - ) - clay.Text( - "Mix elements with standard C code like loops, conditionals and functions.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}), - ) - clay.Text( - "Create your own library of re-usable components from UI primitives like text, images and rectangles.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}), - ) - } - if clay.UI(clay.ID("SyntaxPageRightImage"))({ layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) { - if clay.UI(clay.ID("SyntaxPageRightImageInner"))({ - layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } }, - aspectRatio = { 1136.0 / 1194.0 }, - image = { imageData = &syntaxImage }, - }) {} - } + if clay.UI(clay.ID("SyntaxPageLeftText"))({layout = {sizing = {width = widthSizing}, layoutDirection = .TopToBottom, childGap = 8}}) { + clay.Text("Declarative Syntax", titleTextConfig) + if clay.UI(clay.ID("SyntaxSpacer"))({layout = {sizing = {width = clay.SizingGrow({max = 16})}}}) {} + clay.Text("Flexible and readable declarative syntax with nested UI element hierarchies.", {fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}) + clay.Text("Mix elements with standard C code like loops, conditionals and functions.", {fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}) + clay.Text( + "Create your own library of re-usable components from UI primitives like text, images and rectangles.", + {fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}, + ) + } + if clay.UI(clay.ID("SyntaxPageRightImage"))({layout = {sizing = {width = widthSizing}, childAlignment = {x = .Center}}}) { + if clay.UI(clay.ID("SyntaxPageRightImageInner"))( + {layout = {sizing = {width = clay.SizingGrow({max = 568})}}, aspectRatio = {1136.0 / 1194.0}, image = {imageData = &syntaxImage}}, + ) {} + } } DeclarativeSyntaxPageDesktop :: proc() { - if clay.UI(clay.ID("SyntaxPageDesktop"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } }, - }) { - if clay.UI(clay.ID("SyntaxPage"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingGrow() }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 }, - border = border2pxRed, - }) { - DeclarativeSyntaxPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5)) - } - } + if clay.UI(clay.ID("SyntaxPageDesktop"))( + {layout = {sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .Center}, padding = {left = 50, right = 50}}}, + ) { + if clay.UI(clay.ID("SyntaxPage"))( + {layout = {sizing = {clay.SizingGrow(), clay.SizingGrow()}, childAlignment = {y = .Center}, padding = clay.PaddingAll(32), childGap = 32}, border = border2pxRed}, + ) { + DeclarativeSyntaxPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5)) + } + } } DeclarativeSyntaxPageMobile :: proc() { - if clay.UI(clay.ID("SyntaxPageMobile"))({ - layout = { - layoutDirection = .TopToBottom, - sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, - childAlignment = { x = .Center, y = .Center }, - padding = { 16, 16, 32, 32 }, - childGap = 16, - }, - }) { - DeclarativeSyntaxPage({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}, clay.SizingGrow({})) - } + if clay.UI(clay.ID("SyntaxPageMobile"))( + { + layout = { + layoutDirection = .TopToBottom, + sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, + childAlignment = {x = .Center, y = .Center}, + padding = {16, 16, 32, 32}, + childGap = 16, + }, + }, + ) { + DeclarativeSyntaxPage({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}, clay.SizingGrow({})) + } } ColorLerp :: proc(a: clay.Color, b: clay.Color, amount: f32) -> clay.Color { - return clay.Color{a.r + (b.r - a.r) * amount, a.g + (b.g - a.g) * amount, a.b + (b.b - a.b) * amount, a.a + (b.a - a.a) * amount} + return clay.Color{a.r + (b.r - a.r) * amount, a.g + (b.g - a.g) * amount, a.b + (b.b - a.b) * amount, a.a + (b.a - a.a) * amount} } 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) { - if clay.UI(clay.ID("PerformanceLeftText"))({ layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) { - clay.Text("High Performance", clay.TextConfig(titleTextConfig)) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } }}) {} - clay.Text( - "Fast enough to recompute your entire UI every frame.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}), - ) - clay.Text( - "Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}), - ) - clay.Text( - "Simplify animations and reactive UI design by avoiding the standard performance hacks.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}), - ) - } - if clay.UI(clay.ID("PerformanceRightImageOuter"))({ layout = { sizing = { width = widthSizing }, childAlignment = { x = .Center } } }) { - if clay.UI(clay.ID("PerformanceRightBorder"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(400) } }, - border = { COLOR_LIGHT, {2, 2, 2, 2, 2} }, - }) { - if clay.UI(clay.ID("AnimationDemoContainerLeft"))({ - 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), - }) { - clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT})) - } - if clay.UI(clay.ID("AnimationDemoContainerRight"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingGrow() }, childAlignment = { y = .Center }, padding = clay.PaddingAll(16) }, - backgroundColor = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue), - }) { - clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT})) - } - } - } + if clay.UI(clay.ID("PerformanceLeftText"))({layout = {sizing = {width = widthSizing}, layoutDirection = .TopToBottom, childGap = 8}}) { + clay.Text("High Performance", titleTextConfig) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow({max = 16})}}}) {} + clay.Text("Fast enough to recompute your entire UI every frame.", {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}) + clay.Text("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free.", {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}) + clay.Text("Simplify animations and reactive UI design by avoiding the standard performance hacks.", {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_LIGHT}) + } + if clay.UI(clay.ID("PerformanceRightImageOuter"))({layout = {sizing = {width = widthSizing}, childAlignment = {x = .Center}}}) { + if clay.UI(clay.ID("PerformanceRightBorder"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(400)}}, border = {COLOR_LIGHT, {2, 2, 2, 2, 2}}}) { + if clay.UI(clay.ID("AnimationDemoContainerLeft"))( + { + 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), + }, + ) { + clay.Text(LOREM_IPSUM_TEXT, {fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}) + } + if clay.UI(clay.ID("AnimationDemoContainerRight"))( + { + layout = {sizing = {clay.SizingGrow(), clay.SizingGrow()}, childAlignment = {y = .Center}, padding = clay.PaddingAll(16)}, + backgroundColor = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue), + }, + ) { + clay.Text(LOREM_IPSUM_TEXT, {fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}) + } + } + } } HighPerformancePageDesktop :: proc(lerpValue: f32) { - if clay.UI(clay.ID("PerformanceDesktop"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { 82, 82, 32, 32 }, childGap = 64 }, - backgroundColor = COLOR_RED, - }) { - HighPerformancePage(lerpValue, {fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_LIGHT}, clay.SizingPercent(0.5)) - } + if clay.UI(clay.ID("PerformanceDesktop"))( + { + layout = {sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .Center}, padding = {82, 82, 32, 32}, childGap = 64}, + backgroundColor = COLOR_RED, + }, + ) { + HighPerformancePage(lerpValue, {fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_LIGHT}, clay.SizingPercent(0.5)) + } } HighPerformancePageMobile :: proc(lerpValue: f32) { - if clay.UI(clay.ID("PerformanceMobile"))({ - layout = { - layoutDirection = .TopToBottom, - sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, - childAlignment = { x = .Center, y = .Center }, - padding = { 16, 16, 32, 32 }, - childGap = 32, - }, - backgroundColor = COLOR_RED, - }) { - HighPerformancePage(lerpValue, {fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_LIGHT}, clay.SizingGrow({})) - } + if clay.UI(clay.ID("PerformanceMobile"))( + { + layout = { + layoutDirection = .TopToBottom, + sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, + childAlignment = {x = .Center, y = .Center}, + padding = {16, 16, 32, 32}, + childGap = 32, + }, + backgroundColor = COLOR_RED, + }, + ) { + HighPerformancePage(lerpValue, {fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_LIGHT}, clay.SizingGrow({})) + } } RendererButtonActive :: proc(index: i32, $text: string) { - if clay.UI()({ - layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) }, - backgroundColor = COLOR_RED, - cornerRadius = clay.CornerRadiusAll(10) - }) { - clay.Text(text, clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_LIGHT})) - } + if clay.UI()({layout = {sizing = {width = clay.SizingFixed(300)}, padding = clay.PaddingAll(16)}, backgroundColor = COLOR_RED, cornerRadius = clay.CornerRadiusAll(10)}) { + clay.Text(text, {fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_LIGHT}) + } } RendererButtonInactive :: proc(index: u32, $text: string) { - if clay.UI()({ border = border2pxRed }) { - if clay.UI(clay.ID("RendererButtonInactiveInner", index))({ - layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) }, - backgroundColor = COLOR_LIGHT, - cornerRadius = clay.CornerRadiusAll(10) - }) { - clay.Text(text, clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED})) - } - } + if clay.UI()({border = border2pxRed}) { + if clay.UI(clay.ID("RendererButtonInactiveInner", index))( + {layout = {sizing = {width = clay.SizingFixed(300)}, padding = clay.PaddingAll(16)}, backgroundColor = COLOR_LIGHT, cornerRadius = clay.CornerRadiusAll(10)}, + ) { + clay.Text(text, clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED})) + } + } } RendererPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) { - if clay.UI(clay.ID("RendererLeftText"))({ layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) { - clay.Text("Renderer & Platform Agnostic", clay.TextConfig(titleTextConfig)) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 16 }) } } }) {} - clay.Text( - "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.Text( - "Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more.", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}), - ) - clay.Text( - "There's even an HTML renderer - you're looking at it right now!", - clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}), - ) - } - if clay.UI(clay.ID("RendererRightText"))({ - 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})) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow({ max = 32 }) } } }) {} - RendererButtonActive(0, "Raylib Renderer") - } + if clay.UI(clay.ID("RendererLeftText"))({layout = {sizing = {width = widthSizing}, layoutDirection = .TopToBottom, childGap = 8}}) { + clay.Text("Renderer & Platform Agnostic", titleTextConfig) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow({max = 16})}}}) {} + clay.Text("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE.", {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}) + clay.Text( + "Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more.", + {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}, + ) + clay.Text("There's even an HTML renderer - you're looking at it right now!", {fontSize = 28, fontId = FONT_ID_BODY_36, textColor = COLOR_RED}) + } + if clay.UI(clay.ID("RendererRightText"))({layout = {sizing = {width = widthSizing}, childAlignment = {x = .Center}, layoutDirection = .TopToBottom, childGap = 16}}) { + clay.Text("Try changing renderer!", {fontSize = 36, fontId = FONT_ID_BODY_36, textColor = COLOR_ORANGE}) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow({max = 32})}}}) {} + RendererButtonActive(0, "Raylib Renderer") + } } RendererPageDesktop :: proc() { - if clay.UI(clay.ID("RendererPageDesktop"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, childAlignment = { y = .Center }, padding = { left = 50, right = 50 } }, - }) { - if clay.UI(clay.ID("RendererPage"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingGrow() }, childAlignment = { y = .Center }, padding = clay.PaddingAll(32), childGap = 32 }, - border = { COLOR_RED, { left = 2, right = 2 } }, - }) { - RendererPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5)) - } - } + if clay.UI(clay.ID("RendererPageDesktop"))( + {layout = {sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .Center}, padding = {left = 50, right = 50}}}, + ) { + if clay.UI(clay.ID("RendererPage"))( + { + layout = {sizing = {clay.SizingGrow(), clay.SizingGrow()}, childAlignment = {y = .Center}, padding = clay.PaddingAll(32), childGap = 32}, + border = {COLOR_RED, {left = 2, right = 2}}, + }, + ) { + RendererPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5)) + } + } } RendererPageMobile :: proc() { - if clay.UI(clay.ID("RendererMobile"))({ - layout = { - layoutDirection = .TopToBottom, - sizing = { clay.SizingGrow(), clay.SizingFit({ min = cast(f32)windowHeight - 50 }) }, - childAlignment = { x = .Center, y = .Center }, - padding = { 16, 16, 32, 32 }, - childGap = 32, - }, - backgroundColor = COLOR_LIGHT, - }) { - RendererPage({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}, clay.SizingGrow({})) - } + if clay.UI(clay.ID("RendererMobile"))( + { + layout = { + layoutDirection = .TopToBottom, + sizing = {clay.SizingGrow(), clay.SizingFit({min = cast(f32)windowHeight - 50})}, + childAlignment = {x = .Center, y = .Center}, + padding = {16, 16, 32, 32}, + childGap = 32, + }, + backgroundColor = COLOR_LIGHT, + }, + ) { + RendererPage({fontSize = 48, fontId = FONT_ID_TITLE_48, textColor = COLOR_RED}, clay.SizingGrow({})) + } } ScrollbarData :: struct { - clickOrigin: clay.Vector2, - positionOrigin: clay.Vector2, - mouseDown: bool, + clickOrigin: clay.Vector2, + positionOrigin: clay.Vector2, + mouseDown: bool, } scrollbarData := ScrollbarData{} animationLerpValue: f32 = -1.0 -createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) { - mobileScreen := windowWidth < 750 - clay.BeginLayout() - if clay.UI(clay.ID("OuterContainer"))({ - layout = { layoutDirection = .TopToBottom, sizing = { clay.SizingGrow(), clay.SizingGrow() } }, - backgroundColor = COLOR_LIGHT, - }) { - if clay.UI(clay.ID("Header"))({ - layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(50) }, childAlignment = { y = .Center }, childGap = 24, padding = { left = 32, right = 32 } }, - }) { - clay.Text("Clay", &headerTextConfig) - if clay.UI()({ layout = { sizing = { width = clay.SizingGrow() } } }) {} +createLayout :: proc(lerpValue: f32, frametime: f32) -> clay.ClayArray(clay.RenderCommand) { + mobileScreen := windowWidth < 750 + clay.BeginLayout() + if clay.UI(clay.ID("OuterContainer"))({layout = {layoutDirection = .TopToBottom, sizing = {clay.SizingGrow(), clay.SizingGrow()}}, backgroundColor = COLOR_LIGHT}) { + if clay.UI(clay.ID("Header"))( + {layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(50)}, childAlignment = {y = .Center}, childGap = 24, padding = {left = 32, right = 32}}}, + ) { + clay.Text("Clay", headerTextConfig) + if clay.UI()({layout = {sizing = {width = clay.SizingGrow()}}}) {} - if (!mobileScreen) { - if clay.UI(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}})) - } - if clay.UI(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}})) - } - } - if clay.UI(clay.ID("LinkGithubOuter"))({ - layout = { padding = { 16, 16, 6, 6 } }, - border = border2pxRed, - backgroundColor = clay.Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT, - cornerRadius = clay.CornerRadiusAll(10) - }) { - clay.Text("Github", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}})) - } - } - if clay.UI(clay.ID("TopBorder1"))({ layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_5 } ) {} - if clay.UI(clay.ID("TopBorder2"))({ layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_4 } ) {} - if clay.UI(clay.ID("TopBorder3"))({ layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_3 } ) {} - if clay.UI(clay.ID("TopBorder4"))({ layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_2 } ) {} - if clay.UI(clay.ID("TopBorder5"))({ layout = { sizing = { clay.SizingGrow(), clay.SizingFixed(4) } }, backgroundColor = COLOR_TOP_BORDER_1 } ) {} - if clay.UI(clay.ID("ScrollContainerBackgroundRectangle"))({ - clip = { vertical = true, childOffset = clay.GetScrollOffset() }, - layout = { sizing = { clay.SizingGrow(), clay.SizingGrow() }, layoutDirection = clay.LayoutDirection.TopToBottom }, - backgroundColor = COLOR_LIGHT, - border = { COLOR_RED, { betweenChildren = 2} }, - }) { - if (!mobileScreen) { - LandingPageDesktop() - FeatureBlocksDesktop() - DeclarativeSyntaxPageDesktop() - HighPerformancePageDesktop(lerpValue) - RendererPageDesktop() - } else { - LandingPageMobile() - FeatureBlocksMobile() - DeclarativeSyntaxPageMobile() - HighPerformancePageMobile(lerpValue) - RendererPageMobile() - } - } - } - return clay.EndLayout() + if (!mobileScreen) { + if clay.UI(clay.ID("LinkExamplesOuter"))({backgroundColor = {0, 0, 0, 0}}) { + clay.Text("Examples", {fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}) + } + if clay.UI(clay.ID("LinkDocsOuter"))({backgroundColor = {0, 0, 0, 0}}) { + clay.Text("Docs", {fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}) + } + } + if clay.UI(clay.ID("LinkGithubOuter"))( + { + layout = {padding = {16, 16, 6, 6}}, + border = border2pxRed, + backgroundColor = clay.Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT, + cornerRadius = clay.CornerRadiusAll(10), + }, + ) { + clay.Text("Github", {fontId = FONT_ID_BODY_24, fontSize = 24, textColor = {61, 26, 5, 255}}) + } + } + if clay.UI(clay.ID("TopBorder1"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(4)}}, backgroundColor = COLOR_TOP_BORDER_5}) {} + if clay.UI(clay.ID("TopBorder2"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(4)}}, backgroundColor = COLOR_TOP_BORDER_4}) {} + if clay.UI(clay.ID("TopBorder3"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(4)}}, backgroundColor = COLOR_TOP_BORDER_3}) {} + if clay.UI(clay.ID("TopBorder4"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(4)}}, backgroundColor = COLOR_TOP_BORDER_2}) {} + if clay.UI(clay.ID("TopBorder5"))({layout = {sizing = {clay.SizingGrow(), clay.SizingFixed(4)}}, backgroundColor = COLOR_TOP_BORDER_1}) {} + if clay.UI(clay.ID("ScrollContainerBackgroundRectangle"))( + { + clip = {vertical = true, childOffset = clay.GetScrollOffset()}, + layout = {sizing = {clay.SizingGrow(), clay.SizingGrow()}, layoutDirection = clay.LayoutDirection.TopToBottom}, + backgroundColor = COLOR_LIGHT, + border = {COLOR_RED, {betweenChildren = 2}}, + }, + ) { + if (!mobileScreen) { + LandingPageDesktop() + FeatureBlocksDesktop() + DeclarativeSyntaxPageDesktop() + HighPerformancePageDesktop(lerpValue) + RendererPageDesktop() + } else { + LandingPageMobile() + FeatureBlocksMobile() + DeclarativeSyntaxPageMobile() + HighPerformancePageMobile(lerpValue) + RendererPageMobile() + } + } + } + return clay.EndLayout(frametime) } loadFont :: proc(fontId: u16, fontSize: u16, path: cstring) { - assign_at(&raylib_fonts,fontId,Raylib_Font{ - font = raylib.LoadFontEx(path, cast(i32)fontSize * 2, nil, 0), - fontId = cast(u16)fontId, - }) - raylib.SetTextureFilter(raylib_fonts[fontId].font.texture, raylib.TextureFilter.TRILINEAR) + assign_at(&raylib_fonts, fontId, Raylib_Font{font = raylib.LoadFontEx(path, cast(i32)fontSize * 2, nil, 0), fontId = cast(u16)fontId}) + raylib.SetTextureFilter(raylib_fonts[fontId].font.texture, raylib.TextureFilter.TRILINEAR) } errorHandler :: proc "c" (errorData: clay.ErrorData) { - if (errorData.errorType == clay.ErrorType.DuplicateId) { - // etc - } + if (errorData.errorType == clay.ErrorType.DuplicateId) { + // etc + } } main :: proc() { - minMemorySize: c.size_t = cast(c.size_t)clay.MinMemorySize() - memory := make([^]u8, minMemorySize) - arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory) - clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler }) - clay.SetMeasureTextFunction(measure_text, nil) + minMemorySize: c.size_t = cast(c.size_t)clay.MinMemorySize() + memory := make([^]u8, minMemorySize) + arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory) + clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, {handler = errorHandler}) + clay.SetMeasureTextFunction(measure_text, nil) - raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .MSAA_4X_HINT}) - raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example") - raylib.SetTargetFPS(raylib.GetMonitorRefreshRate(0)) - loadFont(FONT_ID_TITLE_56, 56, "resources/Calistoga-Regular.ttf") - loadFont(FONT_ID_TITLE_52, 52, "resources/Calistoga-Regular.ttf") - loadFont(FONT_ID_TITLE_48, 48, "resources/Calistoga-Regular.ttf") - loadFont(FONT_ID_TITLE_36, 36, "resources/Calistoga-Regular.ttf") - loadFont(FONT_ID_TITLE_32, 32, "resources/Calistoga-Regular.ttf") - loadFont(FONT_ID_BODY_36, 36, "resources/Quicksand-Semibold.ttf") - loadFont(FONT_ID_BODY_30, 30, "resources/Quicksand-Semibold.ttf") - loadFont(FONT_ID_BODY_28, 28, "resources/Quicksand-Semibold.ttf") - loadFont(FONT_ID_BODY_24, 24, "resources/Quicksand-Semibold.ttf") - loadFont(FONT_ID_BODY_16, 16, "resources/Quicksand-Semibold.ttf") + raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .MSAA_4X_HINT}) + raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example") + raylib.SetTargetFPS(raylib.GetMonitorRefreshRate(0)) + loadFont(FONT_ID_TITLE_56, 56, "resources/Calistoga-Regular.ttf") + loadFont(FONT_ID_TITLE_52, 52, "resources/Calistoga-Regular.ttf") + loadFont(FONT_ID_TITLE_48, 48, "resources/Calistoga-Regular.ttf") + loadFont(FONT_ID_TITLE_36, 36, "resources/Calistoga-Regular.ttf") + loadFont(FONT_ID_TITLE_32, 32, "resources/Calistoga-Regular.ttf") + loadFont(FONT_ID_BODY_36, 36, "resources/Quicksand-Semibold.ttf") + loadFont(FONT_ID_BODY_30, 30, "resources/Quicksand-Semibold.ttf") + loadFont(FONT_ID_BODY_28, 28, "resources/Quicksand-Semibold.ttf") + loadFont(FONT_ID_BODY_24, 24, "resources/Quicksand-Semibold.ttf") + loadFont(FONT_ID_BODY_16, 16, "resources/Quicksand-Semibold.ttf") - syntaxImage = raylib.LoadTexture("resources/declarative.png") - checkImage1 = raylib.LoadTexture("resources/check_1.png") - checkImage2 = raylib.LoadTexture("resources/check_2.png") - checkImage3 = raylib.LoadTexture("resources/check_3.png") - checkImage4 = raylib.LoadTexture("resources/check_4.png") - checkImage5 = raylib.LoadTexture("resources/check_5.png") + syntaxImage = raylib.LoadTexture("resources/declarative.png") + checkImage1 = raylib.LoadTexture("resources/check_1.png") + checkImage2 = raylib.LoadTexture("resources/check_2.png") + checkImage3 = raylib.LoadTexture("resources/check_3.png") + checkImage4 = raylib.LoadTexture("resources/check_4.png") + checkImage5 = raylib.LoadTexture("resources/check_5.png") - debugModeEnabled: bool = false + debugModeEnabled: bool = false - for !raylib.WindowShouldClose() { - defer free_all(context.temp_allocator) + for !raylib.WindowShouldClose() { + defer free_all(context.temp_allocator) - animationLerpValue += raylib.GetFrameTime() - if animationLerpValue > 1 { - animationLerpValue = animationLerpValue - 2 - } - windowWidth = raylib.GetScreenWidth() - windowHeight = raylib.GetScreenHeight() - if (raylib.IsKeyPressed(.D)) { - debugModeEnabled = !debugModeEnabled - clay.SetDebugModeEnabled(debugModeEnabled) - } - clay.SetPointerState(transmute(clay.Vector2)raylib.GetMousePosition(), raylib.IsMouseButtonDown(raylib.MouseButton.LEFT)) - clay.UpdateScrollContainers(false, transmute(clay.Vector2)raylib.GetMouseWheelMoveV(), raylib.GetFrameTime()) - clay.SetLayoutDimensions({cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}) - renderCommands: clay.ClayArray(clay.RenderCommand) = createLayout(animationLerpValue < 0 ? (animationLerpValue + 1) : (1 - animationLerpValue)) - raylib.BeginDrawing() - clay_raylib_render(&renderCommands) - raylib.EndDrawing() - } + animationLerpValue += raylib.GetFrameTime() + if animationLerpValue > 1 { + animationLerpValue = animationLerpValue - 2 + } + windowWidth = raylib.GetScreenWidth() + windowHeight = raylib.GetScreenHeight() + if (raylib.IsKeyPressed(.D)) { + debugModeEnabled = !debugModeEnabled + clay.SetDebugModeEnabled(debugModeEnabled) + } + clay.SetPointerState(transmute(clay.Vector2)raylib.GetMousePosition(), raylib.IsMouseButtonDown(raylib.MouseButton.LEFT)) + clay.UpdateScrollContainers(false, transmute(clay.Vector2)raylib.GetMouseWheelMoveV(), raylib.GetFrameTime()) + clay.SetLayoutDimensions({cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}) + renderCommands := createLayout(animationLerpValue < 0 ? (animationLerpValue + 1) : (1 - animationLerpValue), raylib.GetFrameTime()) + raylib.BeginDrawing() + clay_raylib_render(&renderCommands) + raylib.EndDrawing() + } } diff --git a/bindings/odin/examples/clay-official-website/clay_renderer_raylib.odin b/bindings/odin/examples/clay-official-website/clay_renderer_raylib.odin index 135ab30..a01f0c8 100644 --- a/bindings/odin/examples/clay-official-website/clay_renderer_raylib.odin +++ b/bindings/odin/examples/clay-official-website/clay_renderer_raylib.odin @@ -1,19 +1,19 @@ package main -import "core:unicode/utf8" -import "base:runtime" import clay "../../clay-odin" +import "base:runtime" import "core:math" import "core:strings" +import "core:unicode/utf8" import rl "vendor:raylib" Raylib_Font :: struct { - fontId: u16, - font: rl.Font, + fontId: u16, + font: rl.Font, } clay_color_to_rl_color :: proc(color: clay.Color) -> rl.Color { - return {u8(color.r), u8(color.g), u8(color.b), u8(color.a)} + return {u8(color.r), u8(color.g), u8(color.b), u8(color.a)} } raylib_fonts := [dynamic]Raylib_Font{} @@ -22,24 +22,24 @@ raylib_fonts := [dynamic]Raylib_Font{} measure_text :: measure_text_ascii measure_text_unicode :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions { - // Needed for grapheme_count - context = runtime.default_context() - + // Needed for grapheme_count + context = runtime.default_context() + line_width: f32 = 0 - + font := raylib_fonts[config.fontId].font text_str := string(text.chars[:text.length]) - // This function seems somewhat expensive, if you notice performance issues, you could assume - // - 1 codepoint per visual character (no grapheme clusters), where you can get the length from the loop - // - 1 byte per visual character (ascii), where you can get the length with `text.length` - // see `measure_text_ascii` - grapheme_count, _, _ := utf8.grapheme_count(text_str) + // This function seems somewhat expensive, if you notice performance issues, you could assume + // - 1 codepoint per visual character (no grapheme clusters), where you can get the length from the loop + // - 1 byte per visual character (ascii), where you can get the length with `text.length` + // see `measure_text_ascii` + grapheme_count, _, _ := utf8.grapheme_count(text_str) for letter, byte_idx in text_str { glyph_index := rl.GetGlyphIndex(font, letter) - glyph := font.glyphs[glyph_index] + glyph := font.glyphs[glyph_index] if glyph.advanceX != 0 { line_width += f32(glyph.advanceX) @@ -50,25 +50,25 @@ measure_text_unicode :: proc "c" (text: clay.StringSlice, config: ^clay.TextElem scaleFactor := f32(config.fontSize) / f32(font.baseSize) - // Note: - // I'd expect this to be `grapheme_count - 1`, - // but that seems to be one letterSpacing too small - // maybe that's a raylib bug, maybe that's Clay? + // Note: + // I'd expect this to be `grapheme_count - 1`, + // but that seems to be one letterSpacing too small + // maybe that's a raylib bug, maybe that's Clay? total_spacing := f32(grapheme_count) * f32(config.letterSpacing) return {width = line_width * scaleFactor + total_spacing, height = f32(config.fontSize)} } -measure_text_ascii :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions { +measure_text_ascii :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: rawptr) -> clay.Dimensions { line_width: f32 = 0 - + font := raylib_fonts[config.fontId].font text_str := string(text.chars[:text.length]) - for i in 0.. 0 { + tint = overlay_colors[len(overlay_colors) - 1] + } + if tint == 0 { + tint = {255, 255, 255, 255} + } - imageTexture := (^rl.Texture2D)(config.imageData) - rl.DrawTextureEx(imageTexture^, {bounds.x, bounds.y}, 0, bounds.width / f32(imageTexture.width), clay_color_to_rl_color(tint)) - case .ScissorStart: - rl.BeginScissorMode(i32(math.round(bounds.x)), i32(math.round(bounds.y)), i32(math.round(bounds.width)), i32(math.round(bounds.height))) - case .ScissorEnd: - rl.EndScissorMode() - case .Rectangle: - config := render_command.renderData.rectangle - if config.cornerRadius.topLeft > 0 { - radius: f32 = (config.cornerRadius.topLeft * 2) / min(bounds.width, bounds.height) - draw_rect_rounded(bounds.x, bounds.y, bounds.width, bounds.height, radius, config.backgroundColor) - } else { - draw_rect(bounds.x, bounds.y, bounds.width, bounds.height, config.backgroundColor) - } - case .Border: - config := render_command.renderData.border - // Left border - if config.width.left > 0 { - draw_rect( - bounds.x, - bounds.y + config.cornerRadius.topLeft, - f32(config.width.left), - bounds.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft, - config.color, - ) - } - // Right border - if config.width.right > 0 { - draw_rect( - bounds.x + bounds.width - f32(config.width.right), - bounds.y + config.cornerRadius.topRight, - f32(config.width.right), - bounds.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight, - config.color, - ) - } - // Top border - if config.width.top > 0 { - draw_rect( - bounds.x + config.cornerRadius.topLeft, - bounds.y, - bounds.width - config.cornerRadius.topLeft - config.cornerRadius.topRight, - f32(config.width.top), - config.color, - ) - } - // Bottom border - if config.width.bottom > 0 { - draw_rect( - bounds.x + config.cornerRadius.bottomLeft, - bounds.y + bounds.height - f32(config.width.bottom), - bounds.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight, - f32(config.width.bottom), - config.color, - ) - } + imageTexture := (^rl.Texture2D)(config.imageData) + rl.DrawTextureEx(imageTexture^, {bounds.x, bounds.y}, 0, bounds.width / f32(imageTexture.width), clay_color_to_rl_color(tint)) + case .ScissorStart: + rl.BeginScissorMode(i32(math.round(bounds.x)), i32(math.round(bounds.y)), i32(math.round(bounds.width)), i32(math.round(bounds.height))) + case .ScissorEnd: + rl.EndScissorMode() + case .Rectangle: + config := render_command.renderData.rectangle + if config.cornerRadius.topLeft > 0 { + radius: f32 = (config.cornerRadius.topLeft * 2) / min(bounds.width, bounds.height) + draw_rect_rounded(bounds.x, bounds.y, bounds.width, bounds.height, radius, config.backgroundColor) + } else { + draw_rect(bounds.x, bounds.y, bounds.width, bounds.height, config.backgroundColor) + } + case .Border: + config := render_command.renderData.border + // Left border + if config.width.left > 0 { + draw_rect( + bounds.x, + bounds.y + config.cornerRadius.topLeft, + f32(config.width.left), + bounds.height - config.cornerRadius.topLeft - config.cornerRadius.bottomLeft, + config.color, + ) + } + // Right border + if config.width.right > 0 { + draw_rect( + bounds.x + bounds.width - f32(config.width.right), + bounds.y + config.cornerRadius.topRight, + f32(config.width.right), + bounds.height - config.cornerRadius.topRight - config.cornerRadius.bottomRight, + config.color, + ) + } + // Top border + if config.width.top > 0 { + draw_rect( + bounds.x + config.cornerRadius.topLeft, + bounds.y, + bounds.width - config.cornerRadius.topLeft - config.cornerRadius.topRight, + f32(config.width.top), + config.color, + ) + } + // Bottom border + if config.width.bottom > 0 { + draw_rect( + bounds.x + config.cornerRadius.bottomLeft, + bounds.y + bounds.height - f32(config.width.bottom), + bounds.width - config.cornerRadius.bottomLeft - config.cornerRadius.bottomRight, + f32(config.width.bottom), + config.color, + ) + } - // Rounded Borders - if config.cornerRadius.topLeft > 0 { - draw_arc( - bounds.x + config.cornerRadius.topLeft, - bounds.y + config.cornerRadius.topLeft, - config.cornerRadius.topLeft - f32(config.width.top), - config.cornerRadius.topLeft, - 180, - 270, - config.color, - ) - } - if config.cornerRadius.topRight > 0 { - draw_arc( - bounds.x + bounds.width - config.cornerRadius.topRight, - bounds.y + config.cornerRadius.topRight, - config.cornerRadius.topRight - f32(config.width.top), - config.cornerRadius.topRight, - 270, - 360, - config.color, - ) - } - if config.cornerRadius.bottomLeft > 0 { - draw_arc( - bounds.x + config.cornerRadius.bottomLeft, - bounds.y + bounds.height - config.cornerRadius.bottomLeft, - config.cornerRadius.bottomLeft - f32(config.width.top), - config.cornerRadius.bottomLeft, - 90, - 180, - config.color, - ) - } - if config.cornerRadius.bottomRight > 0 { - draw_arc( - bounds.x + bounds.width - config.cornerRadius.bottomRight, - bounds.y + bounds.height - config.cornerRadius.bottomRight, - config.cornerRadius.bottomRight - f32(config.width.bottom), - config.cornerRadius.bottomRight, - 0.1, - 90, - config.color, - ) - } - case clay.RenderCommandType.Custom: - // Implement custom element rendering here - } - } + // Rounded Borders + if config.cornerRadius.topLeft > 0 { + draw_arc( + bounds.x + config.cornerRadius.topLeft, + bounds.y + config.cornerRadius.topLeft, + config.cornerRadius.topLeft - f32(config.width.top), + config.cornerRadius.topLeft, + 180, + 270, + config.color, + ) + } + if config.cornerRadius.topRight > 0 { + draw_arc( + bounds.x + bounds.width - config.cornerRadius.topRight, + bounds.y + config.cornerRadius.topRight, + config.cornerRadius.topRight - f32(config.width.top), + config.cornerRadius.topRight, + 270, + 360, + config.color, + ) + } + if config.cornerRadius.bottomLeft > 0 { + draw_arc( + bounds.x + config.cornerRadius.bottomLeft, + bounds.y + bounds.height - config.cornerRadius.bottomLeft, + config.cornerRadius.bottomLeft - f32(config.width.top), + config.cornerRadius.bottomLeft, + 90, + 180, + config.color, + ) + } + if config.cornerRadius.bottomRight > 0 { + draw_arc( + bounds.x + bounds.width - config.cornerRadius.bottomRight, + bounds.y + bounds.height - config.cornerRadius.bottomRight, + config.cornerRadius.bottomRight - f32(config.width.bottom), + config.cornerRadius.bottomRight, + 0.1, + 90, + config.color, + ) + } + case .OverlayColorStart: + config := render_command.renderData.overlayColor + append(&overlay_colors, config.color) + case .OverlayColorEnd: + pop(&overlay_colors) + case .Custom: + // Implement custom element rendering here + } + } } // Helper procs, mainly for repeated conversions @(private = "file") -draw_arc :: proc(x, y: f32, inner_rad, outer_rad: f32,start_angle, end_angle: f32, color: clay.Color){ - rl.DrawRing( - {math.round(x),math.round(y)}, - math.round(inner_rad), - outer_rad, - start_angle, - end_angle, - 10, - clay_color_to_rl_color(color), - ) +draw_arc :: proc(x, y: f32, inner_rad, outer_rad: f32, start_angle, end_angle: f32, color: clay.Color) { + rl.DrawRing({math.round(x), math.round(y)}, math.round(inner_rad), outer_rad, start_angle, end_angle, 10, clay_color_to_rl_color(color)) } @(private = "file") draw_rect :: proc(x, y, w, h: f32, color: clay.Color) { - rl.DrawRectangle( - i32(math.round(x)), - i32(math.round(y)), - i32(math.round(w)), - i32(math.round(h)), - clay_color_to_rl_color(color) - ) + rl.DrawRectangle(i32(math.round(x)), i32(math.round(y)), i32(math.round(w)), i32(math.round(h)), clay_color_to_rl_color(color)) } @(private = "file") -draw_rect_rounded :: proc(x,y,w,h: f32, radius: f32, color: clay.Color){ - rl.DrawRectangleRounded({x,y,w,h},radius,8,clay_color_to_rl_color(color)) -} \ No newline at end of file +draw_rect_rounded :: proc(x, y, w, h: f32, radius: f32, color: clay.Color) { + rl.DrawRectangleRounded({x, y, w, h}, radius, 8, clay_color_to_rl_color(color)) +} diff --git a/bindings/odin/odinfmt.json b/bindings/odin/odinfmt.json index ee3d563..a54fa0d 100644 --- a/bindings/odin/odinfmt.json +++ b/bindings/odin/odinfmt.json @@ -2,5 +2,5 @@ "$schema": "https://raw.githubusercontent.com/DanielGavin/ols/master/misc/odinfmt.schema.json", "character_width": 180, "sort_imports": true, - "tabs": false -} \ No newline at end of file + "tabs": true +} diff --git a/clay.h b/clay.h index a82d400..a1555e7 100644 --- a/clay.h +++ b/clay.h @@ -958,6 +958,8 @@ CLAY_DLL_EXPORT void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_ CLAY_DLL_EXPORT Clay_Vector2 Clay_GetScrollOffset(void); // Updates the layout dimensions in response to the window or outer container being resized. CLAY_DLL_EXPORT void Clay_SetLayoutDimensions(Clay_Dimensions dimensions); +// Returns the current dimensions set by Clay_SetLayoutDimensions. +CLAY_DLL_EXPORT Clay_Dimensions Clay_GetLayoutDimensions(void); // Called before starting any layout declarations. CLAY_DLL_EXPORT void Clay_BeginLayout(void); // Called when all layout declarations are finished. @@ -2253,6 +2255,14 @@ bool Clay__FloatEqual(float left, float right) { return subtracted < CLAY__EPSILON && subtracted > -CLAY__EPSILON; } +Clay_SizingAxis Clay__GetElementSizing(Clay_LayoutElement* element, bool xAxis) { + if (element->isTextElement) { + return CLAY__INIT(Clay_SizingAxis) {}; + } else { + return xAxis ? element->config.layout.sizing.width : element->config.layout.sizing.height; + } +} + // Writes out the location of text elements to layout elements buffer 1 void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArray* textElementsOut, Clay__int32_tArray* aspectRatioElementsOut) { Clay_Context* context = Clay_GetCurrentContext(); @@ -2319,7 +2329,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr for (int32_t childOffset = 0; childOffset < parent->children.length; childOffset++) { int32_t childElementIndex = parent->children.elements[childOffset]; Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex); - Clay_SizingAxis childSizing = xAxis ? childElement->config.layout.sizing.width : childElement->config.layout.sizing.height; + Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis); float childSize = xAxis ? childElement->dimensions.width : childElement->dimensions.height; if (textElementsOut && childElement->isTextElement) { @@ -2328,7 +2338,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr Clay__int32_tArray_Add(&bfsBuffer, childElementIndex); } - if (aspectRatioElementsOut && childElement->config.aspectRatio.aspectRatio != 0) { + if (!childElement->isTextElement && aspectRatioElementsOut && childElement->config.aspectRatio.aspectRatio != 0) { Clay__int32_tArray_Add(aspectRatioElementsOut, childElementIndex); } @@ -2364,7 +2374,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr for (int32_t childOffset = 0; childOffset < parent->children.length; childOffset++) { int32_t childElementIndex = parent->children.elements[childOffset]; Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, childElementIndex); - Clay_SizingAxis childSizing = xAxis ? childElement->config.layout.sizing.width : childElement->config.layout.sizing.height; + Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis); float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; if (childSizing.type == CLAY__SIZING_TYPE_PERCENT) { *childSize = (parentSize - totalPaddingAndChildGaps) * childSizing.size.percent; @@ -2423,7 +2433,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr } else if (sizeToDistribute > 0 && growContainerCount > 0) { for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); - Clay__SizingType childSizing = xAxis ? child->config.layout.sizing.width.type : child->config.layout.sizing.height.type; + Clay__SizingType childSizing = Clay__GetElementSizing(child, xAxis).type; if (childSizing != CLAY__SIZING_TYPE_GROW) { Clay__int32_tArray_RemoveSwapback(&resizableContainerBuffer, childIndex--); } @@ -2451,7 +2461,8 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr for (int childIndex = 0; childIndex < resizableContainerBuffer.length; childIndex++) { Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childIndex)); float *childSize = xAxis ? &child->dimensions.width : &child->dimensions.height; - float maxSize = xAxis ? child->config.layout.sizing.width.size.minMax.max : child->config.layout.sizing.height.size.minMax.max; + Clay_SizingAxis childSizing = Clay__GetElementSizing(child, xAxis); + float maxSize = childSizing.size.minMax.max; float previousWidth = *childSize; if (Clay__FloatEqual(*childSize, smallest)) { *childSize += widthToAdd; @@ -2468,7 +2479,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis, float deltaTime, Clay__int32_tArr } else { for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) { Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset)); - Clay_SizingAxis childSizing = xAxis ? childElement->config.layout.sizing.width : childElement->config.layout.sizing.height; + Clay_SizingAxis childSizing = Clay__GetElementSizing(childElement, xAxis); float minSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height; float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height; @@ -2782,7 +2793,7 @@ void Clay__CalculateFinalLayout(float deltaTime, bool useStoredBoundingBoxes, bo while (dfsBuffer.length > 0) { Clay__LayoutElementTreeNode *currentElementTreeNode = Clay__LayoutElementTreeNodeArray_Get(&dfsBuffer, (int)dfsBuffer.length - 1); Clay_LayoutElement *currentElement = currentElementTreeNode->layoutElement; - Clay_LayoutConfig *layoutConfig = ¤tElement->config.layout; + Clay_LayoutConfig *layoutConfig = currentElement->isTextElement ? &CLAY_LAYOUT_DEFAULT : ¤tElement->config.layout; Clay_Vector2 scrollOffset = CLAY__DEFAULT_STRUCT; // DFS is returning back upwards @@ -2888,50 +2899,52 @@ void Clay__CalculateFinalLayout(float deltaTime, bool useStoredBoundingBoxes, bo // This will only be run a single time for each element in downwards DFS order context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true; Clay_BoundingBox currentElementBoundingBox = { currentElementTreeNode->position.x, currentElementTreeNode->position.y, currentElement->dimensions.width, currentElement->dimensions.height }; - bool found = false; - if (useStoredBoundingBoxes && currentElement->config.transition.handler) { - for (int j = 0; j < context->transitionDatas.length; ++j) { - Clay__TransitionDataInternal* transitionData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j); - if (transitionData->elementId == currentElement->id) { - found = true; - if (transitionData->state != CLAY_TRANSITION_STATE_IDLE) { - if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_X) != 0) currentElementBoundingBox.x = transitionData->currentState.boundingBox.x; - if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_Y) != 0) currentElementBoundingBox.y = transitionData->currentState.boundingBox.y; - if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_WIDTH) != 0) currentElementBoundingBox.width = transitionData->currentState.boundingBox.width; - if ((currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) != 0) currentElementBoundingBox.height = transitionData->currentState.boundingBox.height; + Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL; + if (!currentElement->isTextElement) { + if (useStoredBoundingBoxes && currentElement->config.transition.handler) { + bool found = false; + for (int j = 0; j < context->transitionDatas.length; ++j) { + Clay__TransitionDataInternal* transitionData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j); + if (transitionData->elementId == currentElement->id) { + found = true; + if (transitionData->state != CLAY_TRANSITION_STATE_IDLE) { + if ((transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_X) != 0) currentElementBoundingBox.x = transitionData->currentState.boundingBox.x; + if ((transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_Y) != 0) currentElementBoundingBox.y = transitionData->currentState.boundingBox.y; + if ((transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_WIDTH) != 0) currentElementBoundingBox.width = transitionData->currentState.boundingBox.width; + if ((transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_HEIGHT) != 0) currentElementBoundingBox.height = transitionData->currentState.boundingBox.height; + } + break; } - break; + } + // An exiting element that completed its transition this frame - skip tree + if (!found && currentElement->config.transition.exit.setFinalState) { + dfsBuffer.length--; + continue; } } - // An exiting element that completed its transition this frame - skip tree - if (!found && currentElement->config.transition.exit.setFinalState) { - dfsBuffer.length--; - continue; + if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) { + Clay_FloatingElementConfig *floatingElementConfig = ¤tElement->config.floating; + Clay_Dimensions expand = floatingElementConfig->expand; + currentElementBoundingBox.x -= expand.width; + currentElementBoundingBox.width += expand.width * 2; + currentElementBoundingBox.y -= expand.height; + currentElementBoundingBox.height += expand.height * 2; } - } - if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) { - Clay_FloatingElementConfig *floatingElementConfig = ¤tElement->config.floating; - Clay_Dimensions expand = floatingElementConfig->expand; - currentElementBoundingBox.x -= expand.width; - currentElementBoundingBox.width += expand.width * 2; - currentElementBoundingBox.y -= expand.height; - currentElementBoundingBox.height += expand.height * 2; - } - Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL; - // Apply scroll offsets to container - if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) { - // This linear scan could theoretically be slow under very strange conditions, but I can't imagine a real UI with more than a few 10's of scroll containers - for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); - if (mapping->layoutElement == currentElement) { - scrollContainerData = mapping; - mapping->boundingBox = currentElementBoundingBox; - scrollOffset = currentElement->config.clip.childOffset; - if (context->externalScrollHandlingEnabled) { - scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT; + // Apply scroll offsets to container + if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) { + // This linear scan could theoretically be slow under very strange conditions, but I can't imagine a real UI with more than a few 10's of scroll containers + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); + if (mapping->layoutElement == currentElement) { + scrollContainerData = mapping; + mapping->boundingBox = currentElementBoundingBox; + scrollOffset = currentElement->config.clip.childOffset; + if (context->externalScrollHandlingEnabled) { + scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT; + } + break; } - break; } } } @@ -3616,56 +3629,58 @@ void Clay__RenderDebugView(void) { CLAY_TEXT(Clay__IntToString(selectedItem->boundingBox.height), infoTextConfig); CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig); } - // .layoutDirection - CLAY_TEXT(CLAY_STRING("Layout Direction"), infoTitleConfig); - Clay_LayoutConfig *layoutConfig = &selectedItem->layoutElement->config.layout; - CLAY_TEXT(layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM ? CLAY_STRING("TOP_TO_BOTTOM") : CLAY_STRING("LEFT_TO_RIGHT"), infoTextConfig); - // .sizing - CLAY_TEXT(CLAY_STRING("Sizing"), infoTitleConfig); - CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { - CLAY_TEXT(CLAY_STRING("width: "), infoTextConfig); - Clay__RenderDebugLayoutSizing(layoutConfig->sizing.width, infoTextConfig); - } - CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { - CLAY_TEXT(CLAY_STRING("height: "), infoTextConfig); - Clay__RenderDebugLayoutSizing(layoutConfig->sizing.height, infoTextConfig); - } - // .padding - CLAY_TEXT(CLAY_STRING("Padding"), infoTitleConfig); - CLAY(CLAY_ID("Clay__DebugViewElementInfoPadding"), { }) { - CLAY_TEXT(CLAY_STRING("{ left: "), infoTextConfig); - CLAY_TEXT(Clay__IntToString(layoutConfig->padding.left), infoTextConfig); - CLAY_TEXT(CLAY_STRING(", right: "), infoTextConfig); - CLAY_TEXT(Clay__IntToString(layoutConfig->padding.right), infoTextConfig); - CLAY_TEXT(CLAY_STRING(", top: "), infoTextConfig); - CLAY_TEXT(Clay__IntToString(layoutConfig->padding.top), infoTextConfig); - CLAY_TEXT(CLAY_STRING(", bottom: "), infoTextConfig); - CLAY_TEXT(Clay__IntToString(layoutConfig->padding.bottom), infoTextConfig); - CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig); - } - // .childGap - CLAY_TEXT(CLAY_STRING("Child Gap"), infoTitleConfig); - CLAY_TEXT(Clay__IntToString(layoutConfig->childGap), infoTextConfig); - // .childAlignment - CLAY_TEXT(CLAY_STRING("Child Alignment"), infoTitleConfig); - CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { - CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig); - Clay_String alignX = CLAY_STRING("LEFT"); - if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_CENTER) { - alignX = CLAY_STRING("CENTER"); - } else if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_RIGHT) { - alignX = CLAY_STRING("RIGHT"); + if (!selectedItem->layoutElement->isTextElement) { + // .layoutDirection + CLAY_TEXT(CLAY_STRING("Layout Direction"), infoTitleConfig); + Clay_LayoutConfig *layoutConfig = &selectedItem->layoutElement->config.layout; + CLAY_TEXT(layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM ? CLAY_STRING("TOP_TO_BOTTOM") : CLAY_STRING("LEFT_TO_RIGHT"), infoTextConfig); + // .sizing + CLAY_TEXT(CLAY_STRING("Sizing"), infoTitleConfig); + CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { + CLAY_TEXT(CLAY_STRING("width: "), infoTextConfig); + Clay__RenderDebugLayoutSizing(layoutConfig->sizing.width, infoTextConfig); } - CLAY_TEXT(alignX, infoTextConfig); - CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig); - Clay_String alignY = CLAY_STRING("TOP"); - if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_CENTER) { - alignY = CLAY_STRING("CENTER"); - } else if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_BOTTOM) { - alignY = CLAY_STRING("BOTTOM"); + CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { + CLAY_TEXT(CLAY_STRING("height: "), infoTextConfig); + Clay__RenderDebugLayoutSizing(layoutConfig->sizing.height, infoTextConfig); + } + // .padding + CLAY_TEXT(CLAY_STRING("Padding"), infoTitleConfig); + CLAY(CLAY_ID("Clay__DebugViewElementInfoPadding"), { }) { + CLAY_TEXT(CLAY_STRING("{ left: "), infoTextConfig); + CLAY_TEXT(Clay__IntToString(layoutConfig->padding.left), infoTextConfig); + CLAY_TEXT(CLAY_STRING(", right: "), infoTextConfig); + CLAY_TEXT(Clay__IntToString(layoutConfig->padding.right), infoTextConfig); + CLAY_TEXT(CLAY_STRING(", top: "), infoTextConfig); + CLAY_TEXT(Clay__IntToString(layoutConfig->padding.top), infoTextConfig); + CLAY_TEXT(CLAY_STRING(", bottom: "), infoTextConfig); + CLAY_TEXT(Clay__IntToString(layoutConfig->padding.bottom), infoTextConfig); + CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig); + } + // .childGap + CLAY_TEXT(CLAY_STRING("Child Gap"), infoTitleConfig); + CLAY_TEXT(Clay__IntToString(layoutConfig->childGap), infoTextConfig); + // .childAlignment + CLAY_TEXT(CLAY_STRING("Child Alignment"), infoTitleConfig); + CLAY_AUTO_ID({ .layout = { .layoutDirection = CLAY_LEFT_TO_RIGHT } }) { + CLAY_TEXT(CLAY_STRING("{ x: "), infoTextConfig); + Clay_String alignX = CLAY_STRING("LEFT"); + if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_CENTER) { + alignX = CLAY_STRING("CENTER"); + } else if (layoutConfig->childAlignment.x == CLAY_ALIGN_X_RIGHT) { + alignX = CLAY_STRING("RIGHT"); + } + CLAY_TEXT(alignX, infoTextConfig); + CLAY_TEXT(CLAY_STRING(", y: "), infoTextConfig); + Clay_String alignY = CLAY_STRING("TOP"); + if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_CENTER) { + alignY = CLAY_STRING("CENTER"); + } else if (layoutConfig->childAlignment.y == CLAY_ALIGN_Y_BOTTOM) { + alignY = CLAY_STRING("BOTTOM"); + } + CLAY_TEXT(alignY, infoTextConfig); + CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig); } - CLAY_TEXT(alignY, infoTextConfig); - CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig); } } if (selectedItem->layoutElement->isTextElement) { @@ -4042,7 +4057,13 @@ CLAY_WASM_EXPORT("Clay_SetLayoutDimensions") void Clay_SetLayoutDimensions(Clay_Dimensions dimensions) { Clay_Context* context = Clay_GetCurrentContext(); context->rootResizedLastFrame = !Clay__FloatEqual(context->layoutDimensions.width, dimensions.width) || !Clay__FloatEqual(context->layoutDimensions.height, dimensions.height); - Clay_GetCurrentContext()->layoutDimensions = dimensions; + context->layoutDimensions = dimensions; +} + +CLAY_WASM_EXPORT("Clay_SetLayoutDimensions") +Clay_Dimensions Clay_GetLayoutDimensions() { + Clay_Context* context = Clay_GetCurrentContext(); + return context->layoutDimensions; } CLAY_WASM_EXPORT("Clay_SetPointerState") @@ -4507,8 +4528,9 @@ Clay_RenderCommandArray Clay_EndLayout(float deltaTime) { continue; } } - // Transition element exited and doesn't have an exit handler defined, delete the transition data - } else if (hashMapItem->generation <= context->generation) { + // Transition element exited and doesn't have an exit handler defined + // Or, the user deleted the transition handler from one frame to the next + } else if (hashMapItem->generation <= context->generation || !hashMapItem->layoutElement->config.transition.handler) { Clay__TransitionDataInternalArray_RemoveSwapback(&context->transitionDatas, i); i--; continue; @@ -4549,10 +4571,12 @@ Clay_RenderCommandArray Clay_EndLayout(float deltaTime) { transitionData->state = CLAY_TRANSITION_STATE_ENTERING; transitionData->initialState = currentElement->config.transition.enter.setInitialState(transitionData->targetState, currentElement->config.transition.properties); transitionData->currentState = transitionData->initialState; + transitionData->activeProperties = currentElement->config.transition.properties; Clay_ApplyTransitionedPropertiesToElement(currentElement, currentElement->config.transition.properties, transitionData->initialState, &mapItem->boundingBox, transitionData->reparented); } else { transitionData->initialState = targetState; transitionData->currentState = targetState; + transitionData->activeProperties = CLAY_TRANSITION_PROPERTY_NONE; } } else { Clay_Vector2 parentScrollOffset = parentMapItem->layoutElement->config.clip.childOffset; @@ -4563,69 +4587,78 @@ Clay_RenderCommandArray Clay_EndLayout(float deltaTime) { Clay_Vector2 oldRelativePosition = transitionData->oldParentRelativePosition; transitionData->oldParentRelativePosition = newRelativePosition; Clay_TransitionProperty properties = currentElement->config.transition.properties; - int32_t activeProperties = CLAY_TRANSITION_PROPERTY_NONE; + int32_t newActiveProperties = CLAY_TRANSITION_PROPERTY_NONE; if (properties & CLAY_TRANSITION_PROPERTY_X) { - if (!Clay__FloatEqual(oldTargetState.boundingBox.x, targetState.boundingBox.x) && !(Clay__FloatEqual(oldRelativePosition.x, newRelativePosition.x)) && !context->rootResizedLastFrame) { - activeProperties |= CLAY_TRANSITION_PROPERTY_X; + // Don't trigger a transition if... + if ( + // The element's absolute position didn't change + !Clay__FloatEqual(oldTargetState.boundingBox.x, targetState.boundingBox.x) + // The element is still in the same parent container, and it's parent-relative position didn't change (parent moved) + && (!(Clay__FloatEqual(oldRelativePosition.x, newRelativePosition.x)) || transitionData->reparented) + // The position changed was triggered by the outer window resizing + && !context->rootResizedLastFrame + ) { + newActiveProperties |= CLAY_TRANSITION_PROPERTY_X; } } if (properties & CLAY_TRANSITION_PROPERTY_Y) { - if (!Clay__FloatEqual(oldTargetState.boundingBox.y, targetState.boundingBox.y) && !(Clay__FloatEqual(oldRelativePosition.y, newRelativePosition.y)) && !context->rootResizedLastFrame) { - activeProperties |= CLAY_TRANSITION_PROPERTY_Y; + if (!Clay__FloatEqual(oldTargetState.boundingBox.y, targetState.boundingBox.y) && (!(Clay__FloatEqual(oldRelativePosition.y, newRelativePosition.y)) || transitionData->reparented) && !context->rootResizedLastFrame) { + newActiveProperties |= CLAY_TRANSITION_PROPERTY_Y; } } if (properties & CLAY_TRANSITION_PROPERTY_WIDTH) { if (!Clay__FloatEqual(oldTargetState.boundingBox.width, targetState.boundingBox.width) && !context->rootResizedLastFrame) { - activeProperties |= CLAY_TRANSITION_PROPERTY_WIDTH; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_WIDTH; } } if (properties & CLAY_TRANSITION_PROPERTY_HEIGHT) { if (!Clay__FloatEqual(oldTargetState.boundingBox.height, targetState.boundingBox.height) && !context->rootResizedLastFrame) { - activeProperties |= CLAY_TRANSITION_PROPERTY_HEIGHT; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_HEIGHT; } } if (properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) { if (!Clay__MemCmp((char *) &oldTargetState.backgroundColor, (char *)&targetState.backgroundColor, sizeof(Clay_Color))) { - activeProperties |= CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR; } } if (properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) { if (!Clay__MemCmp((char *) &oldTargetState.overlayColor, (char *)&targetState.overlayColor, sizeof(Clay_Color))) { - activeProperties |= CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR; } } if (properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) { if (!Clay__MemCmp((char *) &oldTargetState.borderColor, (char *)&targetState.borderColor, sizeof(Clay_Color))) { - activeProperties |= CLAY_TRANSITION_PROPERTY_BORDER_COLOR; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_BORDER_COLOR; } } if (properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) { if (!Clay__MemCmp((char *) &oldTargetState.borderWidth, (char *)&targetState.borderWidth, sizeof(Clay_BorderWidth))) { - activeProperties |= CLAY_TRANSITION_PROPERTY_BORDER_WIDTH; + newActiveProperties |= CLAY_TRANSITION_PROPERTY_BORDER_WIDTH; } } - if (activeProperties != 0 && transitionData->state != CLAY_TRANSITION_STATE_EXITING) { + if (newActiveProperties != 0 && transitionData->state != CLAY_TRANSITION_STATE_EXITING) { transitionData->elapsedTime = 0; transitionData->initialState = transitionData->currentState; transitionData->state = CLAY_TRANSITION_STATE_TRANSITIONING; - transitionData->activeProperties = (Clay_TransitionProperty)activeProperties; + transitionData->activeProperties = (Clay_TransitionProperty)(transitionData->activeProperties | newActiveProperties); } if (transitionData->state == CLAY_TRANSITION_STATE_IDLE) { transitionData->initialState = targetState; transitionData->currentState = targetState; transitionData->targetState = targetState; + transitionData->activeProperties = CLAY_TRANSITION_PROPERTY_NONE; } else { bool transitionComplete = true; transitionComplete = currentElement->config.transition.handler(CLAY__INIT(Clay_TransitionCallbackArguments) { - transitionData->state, - transitionData->initialState, - &transitionData->currentState, - targetState, - transitionData->elapsedTime, - currentElement->config.transition.duration, - currentElement->config.transition.properties + transitionData->state, + transitionData->initialState, + &transitionData->currentState, + targetState, + transitionData->elapsedTime, + currentElement->config.transition.duration, + transitionData->activeProperties }); Clay_ApplyTransitionedPropertiesToElement(currentElement, currentElement->config.transition.properties, transitionData->currentState, &mapItem->boundingBox, transitionData->reparented); diff --git a/examples/SDL3-simple-demo/main.c b/examples/SDL3-simple-demo/main.c index f9d227c..c787db3 100644 --- a/examples/SDL3-simple-demo/main.c +++ b/examples/SDL3-simple-demo/main.c @@ -157,14 +157,6 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) case SDL_EVENT_WINDOW_RESIZED: Clay_SetLayoutDimensions((Clay_Dimensions) { (float) event->window.data1, (float) event->window.data2 }); break; - case SDL_EVENT_MOUSE_MOTION: - Clay_SetPointerState((Clay_Vector2) { event->motion.x, event->motion.y }, - event->motion.state & SDL_BUTTON_LMASK); - break; - case SDL_EVENT_MOUSE_BUTTON_DOWN: - Clay_SetPointerState((Clay_Vector2) { event->button.x, event->button.y }, - event->button.button == SDL_BUTTON_LEFT); - break; case SDL_EVENT_MOUSE_WHEEL: Clay_UpdateScrollContainers(true, (Clay_Vector2) { event->wheel.x, event->wheel.y }, 0.01f); break; @@ -179,6 +171,15 @@ SDL_AppResult SDL_AppIterate(void *appstate) { AppState *state = appstate; + float mouse_x, mouse_y; + + Uint32 buttons = SDL_GetMouseState(&mouse_x, &mouse_y); + + Clay_SetPointerState( + (Clay_Vector2){.x = mouse_x, .y = mouse_y}, + buttons & SDL_BUTTON_LMASK + ); + Clay_RenderCommandArray render_commands = (show_demo ? ClayVideoDemo_CreateLayout(&state->demoData) : ClayImageSample_CreateLayout() @@ -228,5 +229,6 @@ void SDL_AppQuit(void *appstate, SDL_AppResult result) SDL_free(state); } + TTF_Quit(); }