From def516294bfe383738d9e30e54f9867b9be30b15 Mon Sep 17 00:00:00 2001 From: johan0A Date: Sun, 8 Jun 2025 20:17:50 +0200 Subject: [PATCH] move to clay 0.14 --- build.zig.zon | 6 +- .../raylib-clay-official-website/build.zig | 36 ++-- .../build.zig.zon | 4 +- .../raylib-clay-official-website/src/main.zig | 191 +++++------------ .../src/raylib_render_clay.zig | 198 +++++++++--------- examples/raylib-sidebar-container/build.zig | 36 ++-- .../raylib-sidebar-container/build.zig.zon | 4 +- .../raylib-sidebar-container/src/main.zig | 10 +- .../src/raylib_render_clay.zig | 198 +++++++++--------- src/root.zig | 93 +++++--- 10 files changed, 350 insertions(+), 426 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 28f5e41..dba9c91 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,10 +1,10 @@ .{ .name = .zclay, - .version = "0.0.0", + .version = "0.2.0", .dependencies = .{ .clay = .{ - .url = "git+https://github.com/nicbarker/clay?ref=v0.13#6d23a35d1596f139998b2994a63a1d5a982e713b", - .hash = "N-V-__8AAO23UQAhH_BQUUOoxHaKW4XAbiVmGlGJO2sApBST", + .url = "git+https://github.com/nicbarker/clay?ref=v0.14#b25a31c1a152915cd7dd6796e6592273e5a10aac", + .hash = "N-V-__8AALPgZwA7tLqRlkCCL7OrkEhj4xZ3y_0FxgR42t0W", }, }, .paths = .{ diff --git a/examples/raylib-clay-official-website/build.zig b/examples/raylib-clay-official-website/build.zig index d29b2ea..c147d11 100644 --- a/examples/raylib-clay-official-website/build.zig +++ b/examples/raylib-clay-official-website/build.zig @@ -1,5 +1,6 @@ const std = @import("std"); const B = std.Build; +const rl = @import("raylib"); pub fn build(b: *B) void { const target = b.standardTargetOptions(.{}); @@ -10,7 +11,20 @@ pub fn build(b: *B) void { .target = target, .optimize = optimize, }); - addDependencies(root_module, b, target, optimize); + + const zclay_dep = b.dependency("zclay", .{ + .target = target, + .optimize = optimize, + }); + root_module.addImport("zclay", zclay_dep.module("zclay")); + + const raylib_dep = b.dependency("raylib_zig", .{ + .target = target, + .optimize = optimize, + .platform = .rgfw, + }); + root_module.addImport("raylib", raylib_dep.module("raylib")); + root_module.linkLibrary(raylib_dep.artifact("raylib")); { const exe = b.addExecutable(.{ .name = "zclay-example", .root_module = root_module }); @@ -42,23 +56,3 @@ pub fn build(b: *B) void { check.dependOn(&tests_check.step); } } - -fn addDependencies( - module: *B.Module, - b: *B, - target: B.ResolvedTarget, - optimize: std.builtin.OptimizeMode, -) void { - const zclay_dep = b.dependency("zclay", .{ - .target = target, - .optimize = optimize, - }); - module.addImport("zclay", zclay_dep.module("zclay")); - - const raylib_dep = b.dependency("raylib_zig", .{ - .target = target, - .optimize = optimize, - }); - module.addImport("raylib", raylib_dep.module("raylib")); - module.linkLibrary(raylib_dep.artifact("raylib")); -} diff --git a/examples/raylib-clay-official-website/build.zig.zon b/examples/raylib-clay-official-website/build.zig.zon index e14f82c..12e9f2d 100644 --- a/examples/raylib-clay-official-website/build.zig.zon +++ b/examples/raylib-clay-official-website/build.zig.zon @@ -6,8 +6,8 @@ .path = "../../", }, .raylib_zig = .{ - .url = "git+https://github.com/Not-Nik/raylib-zig#5bbafa4f86eb3e3f41a107bbec6b8822e0f87c93", - .hash = "raylib_zig-5.6.0-dev-KE8REE0uBQD5Lzuc6qSZPtE5li3iPyU4iGQEMPqOPI11", + .url = "git+https://github.com/Not-Nik/raylib-zig#3bf08a304cfe2baf839705063ff999b8d8bc8c54", + .hash = "raylib_zig-5.6.0-dev-KE8REKAqBQAQugfCOjYYVRFOi7iaEJK1EMDcRUq8AOm2", }, }, .paths = .{ diff --git a/examples/raylib-clay-official-website/src/main.zig b/examples/raylib-clay-official-website/src/main.zig index 84ee188..8f33ae5 100644 --- a/examples/raylib-clay-official-website/src/main.zig +++ b/examples/raylib-clay-official-website/src/main.zig @@ -3,16 +3,19 @@ const rl = @import("raylib"); const cl = @import("zclay"); const renderer = @import("raylib_render_clay.zig"); -var syntaxImage: rl.Texture2D = undefined; -var checkImage1: rl.Texture2D = undefined; -var checkImage2: rl.Texture2D = undefined; -var checkImage3: rl.Texture2D = undefined; -var checkImage4: rl.Texture2D = undefined; -var checkImage5: rl.Texture2D = undefined; +var syntax_image: rl.Texture2D = undefined; +var check_image1: rl.Texture2D = undefined; +var check_image2: rl.Texture2D = undefined; +var check_image3: rl.Texture2D = undefined; +var check_image4: rl.Texture2D = undefined; +var check_image5: rl.Texture2D = undefined; var zig_logo_image6: rl.Texture2D = undefined; +var window_height: isize = 0; +var window_width: isize = 0; +var mobile_screen: bool = false; + const FONT_ID_BODY_16 = 0; -const FONT_ID_TITLE_56 = 9; const FONT_ID_TITLE_52 = 1; const FONT_ID_TITLE_48 = 2; const FONT_ID_TITLE_36 = 3; @@ -21,6 +24,7 @@ const FONT_ID_BODY_36 = 5; const FONT_ID_BODY_30 = 6; const FONT_ID_BODY_28 = 7; const FONT_ID_BODY_24 = 8; +const FONT_ID_TITLE_56 = 9; const COLOR_LIGHT = cl.Color{ 244, 235, 230, 255 }; const COLOR_LIGHT_HOVER = cl.Color{ 224, 215, 210, 255 }; @@ -51,22 +55,14 @@ const COLOR_BLOB_BORDER_5 = cl.Color{ 240, 189, 100, 255 }; const border_data = cl.BorderData{ .width = 2, .color = COLOR_RED }; -var window_height: isize = 0; -var window_width: isize = 0; -var mobile_screen: bool = false; - -fn landingPageBlob(index: u32, font_size: u16, font_id: u16, color: cl.Color, image_size: f32, max_width: f32, text: []const u8, image: *rl.Texture2D) void { +fn landingPageBlob(index: u32, font_size: u16, font_id: u16, color: cl.Color, image_size: f32, width: f32, text: []const u8, image: *rl.Texture2D) void { cl.UI()(.{ .id = .IDI("HeroBlob", index), - .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = max_width }) }, .padding = .all(16), .child_gap = 16, .child_alignment = .{ .y = .center } }, + .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = width }) }, .padding = .all(16), .child_gap = 16, .child_alignment = .{ .y = .center } }, .border = .{ .width = .outside(2), .color = color }, .corner_radius = .all(10), })({ - cl.UI()(.{ - .id = .IDI("CheckImage", index), - .layout = .{ .sizing = .{ .w = .fixed(image_size) } }, - .image = .{ .image_data = image, .source_dimensions = .{ .w = 128, .h = 128 } }, - })({}); + cl.UI()(.{ .id = .IDI("CheckImage", index), .layout = .{ .sizing = .{ .w = .fixed(image_size) } }, .aspect_ratio = .{ .aspect_ratio = 128 / 128 }, .image = .{ .image_data = image } })({}); cl.text(text, .{ .font_size = font_size, .font_id = font_id, .color = color }); }); } @@ -74,57 +70,33 @@ fn landingPageBlob(index: u32, font_size: u16, font_id: u16, color: cl.Color, im fn landingPageDesktop() void { cl.UI()(.{ .id = .ID("LandingPage1Desktop"), - .layout = .{ - .sizing = .{ .w = .grow, .h = .fitMinMax(.{ .min = @floatFromInt(window_height - 70) }) }, - .child_alignment = .{ .y = .center }, - .padding = .{ .left = 50, .right = 50 }, - .child_gap = 16, - }, + .layout = .{ .sizing = .{ .w = .grow, .h = .fitMinMax(.{ .min = @floatFromInt(window_height - 70) }) }, .child_alignment = .{ .y = .center }, .padding = .{ .left = 50, .right = 50 } }, })({ cl.UI()(.{ .id = .ID("LandingPage1"), - .layout = .{ - .sizing = .{ .w = .grow, .h = .fitMinMax(.{ .min = @floatFromInt(window_height - 70) }) }, - .direction = .top_to_bottom, - .child_alignment = .{ .x = .center }, - .padding = .all(32), - .child_gap = 32, - }, + .layout = .{ .sizing = .{ .w = .grow, .h = .grow }, .direction = .top_to_bottom, .child_alignment = .{ .x = .center }, .padding = .all(32), .child_gap = 32 }, .border = .{ .width = .{ .left = 2, .right = 2 }, .color = COLOR_RED }, })({ landingPageBlob(0, 30, FONT_ID_BODY_30, COLOR_ZIG_LOGO, 64, 510, "The official Clay website recreated with zclay: clay-zig-bindings", &zig_logo_image6); - cl.UI()(.{ - .id = .ID("ClayPresentation"), - .layout = .{ - .sizing = .grow, - .child_alignment = .{ .y = .center }, - .child_gap = 16, - }, - })({ + cl.UI()(.{ .id = .ID("ClayPresentation"), .layout = .{ .sizing = .grow, .child_alignment = .{ .y = .center }, .child_gap = 16 } })({ cl.UI()(.{ .id = .ID("LeftText"), .layout = .{ .sizing = .{ .w = .percent(0.55) }, .direction = .top_to_bottom, .child_gap = 8 }, })({ - cl.text( - "Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", - .{ .font_size = 56, .font_id = FONT_ID_TITLE_56, .color = COLOR_RED }, - ); + cl.text("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", .{ .font_size = 56, .font_id = FONT_ID_TITLE_56, .color = COLOR_RED }); cl.UI()(.{ .layout = .{ .sizing = .{ .w = .grow, .h = .fixed(32) } } })({}); - cl.text( - "Clay is laying out this webpage right now!", - .{ .font_size = 36, .font_id = FONT_ID_BODY_36, .color = COLOR_ORANGE }, - ); + cl.text("Clay is laying out this webpage right now!", .{ .font_size = 36, .font_id = FONT_ID_BODY_36, .color = COLOR_ORANGE }); }); cl.UI()(.{ .id = .ID("HeroImageOuter"), .layout = .{ .sizing = .{ .w = .percent(0.45) }, .direction = .top_to_bottom, .child_alignment = .{ .x = .center }, .child_gap = 16 }, })({ - landingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, 32, 480, "High performance", &checkImage5); - landingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, 32, 480, "Flexbox-style responsive layout", &checkImage4); - landingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, 32, 480, "Declarative syntax", &checkImage3); - landingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, 32, 480, "Single .h file for C/C++", &checkImage2); - landingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, 32, 480, "Compile to 15kb .wasm", &checkImage1); + landingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, 32, 480, "High performance", &check_image5); + landingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, 32, 480, "Flexbox-style responsive layout", &check_image4); + landingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, 32, 480, "Declarative syntax", &check_image3); + landingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, 32, 480, "Single .h file for C/C++", &check_image2); + landingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, 32, 480, "Compile to 15kb .wasm", &check_image1); }); }); }); @@ -142,31 +114,25 @@ fn landingPageMobile() void { .child_gap = 16, }, })({ - landingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_ZIG_LOGO, 64, 510, "The official Clay website recreated with zclay: clay-zig-bindings", &zig_logo_image6); + landingPageBlob(0, 30, FONT_ID_BODY_30, COLOR_ZIG_LOGO, 64, 510, "The official Clay website recreated with zclay: clay-zig-bindings", &zig_logo_image6); cl.UI()(.{ .id = .ID("LeftText"), .layout = .{ .sizing = .{ .w = .grow }, .direction = .top_to_bottom, .child_gap = 8 }, })({ - cl.text( - "Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", - .{ .font_size = 56, .font_id = FONT_ID_TITLE_56, .color = COLOR_RED }, - ); + cl.text("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance.", .{ .font_size = 56, .font_id = FONT_ID_TITLE_56, .color = COLOR_RED }); cl.UI()(.{ .layout = .{ .sizing = .{ .w = .grow, .h = .fixed(32) } } })({}); - cl.text( - "Clay is laying out this webpage .right now!", - .{ .font_size = 36, .font_id = FONT_ID_BODY_36, .color = COLOR_ORANGE }, - ); + cl.text("Clay is laying out this webpage .right now!", .{ .font_size = 36, .font_id = FONT_ID_BODY_36, .color = COLOR_ORANGE }); }); cl.UI()(.{ .id = .ID("HeroImageOuter"), .layout = .{ .sizing = .{ .w = .grow }, .direction = .top_to_bottom, .child_alignment = .{ .x = .center }, .child_gap = 16 }, })({ - landingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, 32, 480, "High performance", &checkImage5); - landingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, 32, 480, "Flexbox-style responsive layout", &checkImage4); - landingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, 32, 480, "Declarative syntax", &checkImage3); - landingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, 32, 480, "Single .h file for C/C++", &checkImage2); - landingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, 32, 480, "Compile to 15kb .wasm", &checkImage1); + landingPageBlob(1, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_5, 32, 480, "High performance", &check_image5); + landingPageBlob(2, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_4, 32, 480, "Flexbox-style responsive layout", &check_image4); + landingPageBlob(3, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_3, 32, 480, "Declarative syntax", &check_image3); + landingPageBlob(4, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_2, 32, 480, "Single .h file for C/C++", &check_image2); + landingPageBlob(5, 30, FONT_ID_BODY_30, COLOR_BLOB_BORDER_1, 32, 480, "Compile to 15kb .wasm", &check_image1); }); }); } @@ -213,10 +179,7 @@ fn featureBlocks(width_sizing: cl.SizingAxis, outer_padding: u16) void { fn featureBlocksDesktop() void { cl.UI()(.{ .id = .ID("FeatureBlocksOuter"), - .layout = .{ - .sizing = .{ .w = .grow }, - .child_alignment = .{ .y = .center }, - }, + .layout = .{ .sizing = .{ .w = .grow }, .child_alignment = .{ .y = .center } }, .border = .{ .width = .{ .between_children = 2 }, .color = COLOR_RED }, })({ featureBlocks(.percent(0.5), 50); @@ -226,10 +189,7 @@ fn featureBlocksDesktop() void { fn featureBlocksMobile() void { cl.UI()(.{ .id = .ID("FeatureBlocksOuter"), - .layout = .{ - .sizing = .{ .w = .grow }, - .direction = .top_to_bottom, - }, + .layout = .{ .sizing = .{ .w = .grow }, .direction = .top_to_bottom }, .border = .{ .width = .{ .between_children = 2 }, .color = COLOR_RED }, })({ featureBlocks(.grow, 16); @@ -239,9 +199,7 @@ fn featureBlocksMobile() void { fn declarativeSyntaxPage(title_text_config: cl.TextElementConfig, width_sizing: cl.SizingAxis) void { cl.UI()(.{ .id = .ID("SyntaxPageLeftText"), .layout = .{ .sizing = .{ .w = width_sizing }, .direction = .top_to_bottom, .child_gap = 8 } })({ cl.text("Declarative Syntax", title_text_config); - cl.UI()(.{ - .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = 16 }) } }, - })({}); + cl.UI()(.{ .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = 16 }) } } })({}); const text_conf = cl.TextElementConfig{ .font_size = 28, .font_id = FONT_ID_BODY_28, .color = COLOR_RED }; cl.text("Flexible and readable declarative syntax with nested UI element hierarchies.", text_conf); cl.text("Mix elements with standard C code like loops, conditionals and functions.", text_conf); @@ -251,7 +209,8 @@ fn declarativeSyntaxPage(title_text_config: cl.TextElementConfig, width_sizing: cl.UI()(.{ .id = .ID("SyntaxPageRightImage"), .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = 568 }) } }, - .image = .{ .image_data = &syntaxImage, .source_dimensions = .{ .h = 1136, .w = 1194 } }, + .aspect_ratio = .{ .aspect_ratio = 1194 / 1136 }, + .image = .{ .image_data = &syntax_image }, })({}); }); } @@ -296,18 +255,9 @@ fn highPerformancePage(lerp_value: f32, title_text_tonfig: cl.TextElementConfig, cl.UI()(.{ .id = .ID("PerformanceLeftText"), .layout = .{ .sizing = .{ .w = width_sizing }, .direction = .top_to_bottom, .child_gap = 8 } })({ cl.text("High Performance", title_text_tonfig); cl.UI()(.{ .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = 16 }) } } })({}); - cl.text( - "Fast enough to recompute your entire UI every frame.", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }, - ); - cl.text( - "Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free.", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }, - ); - cl.text( - "Simplify animations and reactive UI design by avoiding the standard performance hacks.", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }, - ); + cl.text("Fast enough to recompute your entire UI every frame.", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }); + cl.text("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free.", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }); + cl.text("Simplify animations and reactive UI design by avoiding the standard performance hacks.", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_LIGHT }); }); cl.UI()(.{ .id = .ID("PerformanceRightImageOuter"), .layout = .{ .sizing = .{ .w = width_sizing }, .child_alignment = .{ .x = .center } } })({ cl.UI()(.{ @@ -322,6 +272,7 @@ fn highPerformancePage(lerp_value: f32, title_text_tonfig: cl.TextElementConfig, })({ cl.text(LOREM_IPSUM_TEXT, .{ .font_size = 16, .font_id = FONT_ID_BODY_16, .color = COLOR_LIGHT }); }); + cl.UI()(.{ .id = .ID("AnimationDemoContainerRight"), .layout = .{ .sizing = .{ .w = .grow, .h = .grow }, .child_alignment = .{ .y = .center }, .padding = .all(16) }, @@ -391,18 +342,9 @@ fn rendererPage(title_text_config: cl.TextElementConfig, width_sizing: cl.Sizing cl.UI()(.{ .id = .ID("RendererLeftText"), .layout = .{ .sizing = .{ .w = width_sizing }, .direction = .top_to_bottom, .child_gap = 8 } })({ cl.text("Renderer & Platform Agnostic", title_text_config); cl.UI()(.{ .layout = .{ .sizing = .{ .w = .growMinMax(.{ .max = 16 }) } } })({}); - cl.text( - "Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE.", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }, - ); - cl.text( - "Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more.", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }, - ); - cl.text( - "There's even an HTML renderer - you're looking at it right now!", - .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }, - ); + cl.text("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE.", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }); + cl.text("Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more.", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }); + cl.text("There's even an HTML renderer - you're looking at it right now!", .{ .font_size = 28, .font_id = FONT_ID_BODY_36, .color = COLOR_RED }); }); cl.UI()(.{ .id = .ID("RendererRightText"), @@ -417,11 +359,7 @@ fn rendererPage(title_text_config: cl.TextElementConfig, width_sizing: cl.Sizing fn rendererPageDesktop() void { cl.UI()(.{ .id = .ID("RendererPageDesktop"), - .layout = .{ - .sizing = .{ .w = .grow, .h = .fitMinMax(.{ .min = @floatFromInt(window_height - 50) }) }, - .child_alignment = .{ .y = .center }, - .padding = .{ .left = 50, .right = 50 }, - }, + .layout = .{ .sizing = .{ .w = .grow, .h = .fitMinMax(.{ .min = @floatFromInt(window_height - 50) }) }, .child_alignment = .{ .y = .center }, .padding = .{ .left = 50, .right = 50 } }, })({ cl.UI()(.{ .id = .ID("RendererPage"), @@ -449,7 +387,7 @@ fn rendererPageMobile() void { }); } -fn createLayout(lerp_value: f32) cl.ClayArray(cl.RenderCommand) { +fn createLayout(lerp_value: f32) []cl.RenderCommand { cl.beginLayout(); cl.UI()(.{ .id = .ID("OuterContainer"), @@ -458,18 +396,9 @@ fn createLayout(lerp_value: f32) cl.ClayArray(cl.RenderCommand) { })({ cl.UI()(.{ .id = .ID("Header"), - .layout = .{ - .sizing = .{ .h = .fixed(50), .w = .grow }, - .child_alignment = .{ .y = .center }, - .padding = .{ .left = 32, .right = 32 }, - .child_gap = 24, - }, + .layout = .{ .sizing = .{ .h = .fixed(50), .w = .grow }, .child_alignment = .{ .y = .center }, .padding = .{ .left = 32, .right = 32 }, .child_gap = 24 }, })({ - cl.text("Clay", .{ - .font_id = FONT_ID_BODY_24, - .font_size = 24, - .color = .{ 61, 26, 5, 255 }, - }); + cl.text("Clay", .{ .font_id = FONT_ID_BODY_24, .font_size = 24, .color = .{ 61, 26, 5, 255 } }); cl.UI()(.{ .layout = .{ .sizing = .{ .w = .grow } } })({}); if (!mobile_screen) { @@ -487,10 +416,7 @@ fn createLayout(lerp_value: f32) cl.ClayArray(cl.RenderCommand) { .corner_radius = .all(10), .background_color = if (cl.hovered()) COLOR_LIGHT_HOVER else COLOR_LIGHT, })({ - cl.text( - "Github", - .{ .font_id = FONT_ID_BODY_24, .font_size = 24, .color = .{ 61, 26, 5, 255 } }, - ); + cl.text("Github", .{ .font_id = FONT_ID_BODY_24, .font_size = 24, .color = .{ 61, 26, 5, 255 } }); }); }); inline for (COLORS_TOP_BORDER, 0..) |color, i| { @@ -503,7 +429,7 @@ fn createLayout(lerp_value: f32) cl.ClayArray(cl.RenderCommand) { cl.UI()(.{ .id = .ID("ScrollContainerBackgroundRectangle"), - .scroll = .{ .vertical = true }, + .clip = .{ .vertical = true, .child_offset = cl.getScrollOffset() }, .layout = .{ .sizing = .grow, .direction = .top_to_bottom }, .background_color = COLOR_LIGHT, .border = .{ .width = .{ .between_children = 2 }, .color = COLOR_RED }, @@ -554,7 +480,6 @@ pub fn main() !void { .window_resizable = true, }); rl.initWindow(1000, 1000, "Raylib zig Example"); - rl.setWindowMinSize(300, 100); rl.setTargetFPS(60); // load assets @@ -569,12 +494,12 @@ pub fn main() !void { try loadFont(@embedFile("resources/Quicksand-Semibold.ttf"), FONT_ID_BODY_24, 24); try loadFont(@embedFile("resources/Quicksand-Semibold.ttf"), FONT_ID_BODY_16, 16); - syntaxImage = try loadImage("resources/declarative.png"); - checkImage1 = try loadImage("resources/check_1.png"); - checkImage2 = try loadImage("resources/check_2.png"); - checkImage3 = try loadImage("resources/check_3.png"); - checkImage4 = try loadImage("resources/check_4.png"); - checkImage5 = try loadImage("resources/check_5.png"); + syntax_image = try loadImage("resources/declarative.png"); + check_image1 = try loadImage("resources/check_1.png"); + check_image2 = try loadImage("resources/check_2.png"); + check_image3 = try loadImage("resources/check_3.png"); + check_image4 = try loadImage("resources/check_4.png"); + check_image5 = try loadImage("resources/check_5.png"); zig_logo_image6 = try loadImage("resources/zig-mark.png"); var animation_lerp_value: f32 = -1.0; @@ -611,10 +536,10 @@ pub fn main() !void { .w = @floatFromInt(window_width), .h = @floatFromInt(window_height), }); - var render_commands = createLayout(if (animation_lerp_value < 0) animation_lerp_value + 1 else 1 - animation_lerp_value); + const render_commands = createLayout(if (animation_lerp_value < 0) animation_lerp_value + 1 else 1 - animation_lerp_value); rl.beginDrawing(); - try renderer.clayRaylibRender(&render_commands, allocator); + try renderer.clayRaylibRender(render_commands, allocator); rl.endDrawing(); } } diff --git a/examples/raylib-clay-official-website/src/raylib_render_clay.zig b/examples/raylib-clay-official-website/src/raylib_render_clay.zig index af745e1..a89aad8 100644 --- a/examples/raylib-clay-official-website/src/raylib_render_clay.zig +++ b/examples/raylib-clay-official-website/src/raylib_render_clay.zig @@ -14,10 +14,9 @@ pub fn clayColorToRaylibColor(color: cl.Color) rl.Color { pub var raylib_fonts: [10]?rl.Font = .{null} ** 10; -pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), allocator: std.mem.Allocator) !void { - var i: usize = 0; - while (i < render_commands.length) : (i += 1) { - const render_command = cl.renderCommandArrayGet(render_commands, @intCast(i)); +pub fn clayRaylibRender(render_commands: []cl.RenderCommand, allocator: std.mem.Allocator) !void { + for (0..render_commands.len) |i| { + const render_command = render_commands[i]; const bounding_box = render_command.bounding_box; switch (render_command.command_type) { .none => {}, @@ -27,6 +26,7 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca // Raylib uses standard C strings so isn't compatible with cheap slices, we need to clone the string to append null terminator const cloned = try allocator.dupeZ(u8, text); defer allocator.free(cloned); + const fontToUse: rl.Font = raylib_fonts[config.font_id].?; rl.setTextLineSpacing(config.line_height); rl.drawTextEx( @@ -40,16 +40,18 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca }, .image => { const config = render_command.render_data.image; + var tint = config.background_color; + if (std.mem.eql(f32, &tint, &.{ 0, 0, 0, 0 })) { + tint = .{ 255, 255, 255, 255 }; + } - const image_texture: *const rl.Texture2D = @ptrCast( - @alignCast(config.image_data), - ); + const image_texture: *const rl.Texture2D = @ptrCast(@alignCast(config.image_data)); rl.drawTextureEx( image_texture.*, rl.Vector2{ .x = bounding_box.x, .y = bounding_box.y }, 0, bounding_box.width / @as(f32, @floatFromInt(image_texture.width)), - rl.Color.white, + clayColorToRaylibColor(tint), ); }, .scissor_start => { @@ -88,102 +90,90 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca }, .border => { const config = render_command.render_data.border; - // Left border - if (config.width.left > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x)), - @intFromFloat(@round(bounding_box.y + config.corner_radius.top_left)), - @intCast(config.width.left), - @intFromFloat(@round(bounding_box.height - config.corner_radius.top_left - config.corner_radius.bottom_left)), - clayColorToRaylibColor(config.color), - ); - } - // Right border - if (config.width.right > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + bounding_box.width - @as(f32, @floatFromInt(config.width.right)))), - @intFromFloat(@round(bounding_box.y + config.corner_radius.top_right)), - @intCast(config.width.right), - @intFromFloat(@round(bounding_box.height - config.corner_radius.top_right - config.corner_radius.bottom_right)), - clayColorToRaylibColor(config.color), - ); - } - // Top border - if (config.width.top > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + config.corner_radius.top_left)), - @intFromFloat(@round(bounding_box.y)), - @intFromFloat(@round(bounding_box.width - config.corner_radius.top_left - config.corner_radius.top_right)), - @intCast(config.width.top), - clayColorToRaylibColor(config.color), - ); - } - // Bottom border - if (config.width.bottom > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + config.corner_radius.bottom_left)), - @intFromFloat(@round(bounding_box.y + bounding_box.height - @as(f32, @floatFromInt(config.width.bottom)))), - @intFromFloat(@round(bounding_box.width - config.corner_radius.bottom_left - config.corner_radius.bottom_right)), - @intCast(config.width.bottom), - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.top_left > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + config.corner_radius.top_left), - .y = @round(bounding_box.y + config.corner_radius.top_left), - }, - @round(config.corner_radius.top_left - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.top_left, - 180, - 270, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.top_right > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + bounding_box.width - config.corner_radius.top_right), - .y = @round(bounding_box.y + config.corner_radius.top_right), - }, - @round(config.corner_radius.top_right - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.top_right, - 270, - 360, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.bottom_left > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + config.corner_radius.bottom_left), - .y = @round(bounding_box.y + bounding_box.height - config.corner_radius.bottom_left), - }, - @round(config.corner_radius.bottom_left - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.bottom_left, - 90, - 180, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.bottom_right > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + bounding_box.width - config.corner_radius.bottom_right), - .y = @round(bounding_box.y + bounding_box.height - config.corner_radius.bottom_right), - }, - @round(config.corner_radius.bottom_right - @as(f32, @floatFromInt(config.width.bottom))), - config.corner_radius.bottom_right, - 0.1, - 90, - 10, - clayColorToRaylibColor(config.color), - ); - } + const color = clayColorToRaylibColor(config.color); + const bb = bounding_box; + const corners = config.corner_radius; + + const drawRect = struct { + fn draw(x: f32, y: f32, w: f32, h: f32, c: rl.Color) void { + rl.drawRectangle(@intFromFloat(@round(x)), @intFromFloat(@round(y)), @intFromFloat(@round(w)), @intFromFloat(@round(h)), c); + } + }.draw; + + drawRect( + bb.x, + bb.y + corners.top_left, + @floatFromInt(config.width.left), + bb.height - corners.top_left - corners.bottom_left, + color, + ); + + drawRect( + bb.x + bb.width - @as(f32, @floatFromInt(config.width.right)), + bb.y + corners.top_right, + @floatFromInt(config.width.right), + bb.height - corners.top_right - corners.bottom_right, + color, + ); + + drawRect( + bb.x + corners.top_left, + bb.y, + bb.width - corners.top_left - corners.top_right, + @floatFromInt(config.width.top), + color, + ); + + drawRect( + bb.x + corners.bottom_left, + bb.y + bb.height - @as(f32, @floatFromInt(config.width.bottom)), + bb.width - corners.bottom_left - corners.bottom_right, + @floatFromInt(config.width.bottom), + color, + ); + + const drawCorner = struct { + fn draw(center: rl.Vector2, innerRadius: f32, outerRadius: f32, startAngle: f32, endAngle: f32, c: rl.Color) void { + if (outerRadius <= 0) return; + rl.drawRing(center, @round(innerRadius), @round(outerRadius), startAngle, endAngle, 10, c); + } + }.draw; + + drawCorner( + rl.Vector2{ .x = @round(bb.x + corners.top_left), .y = @round(bb.y + corners.top_left) }, + corners.top_left - @as(f32, @floatFromInt(config.width.top)), + corners.top_left, + 180, + 270, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + bb.width - corners.top_right), .y = @round(bb.y + corners.top_right) }, + corners.top_right - @as(f32, @floatFromInt(config.width.top)), + corners.top_right, + 270, + 360, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + corners.bottom_left), .y = @round(bb.y + bb.height - corners.bottom_left) }, + corners.bottom_left - @as(f32, @floatFromInt(config.width.bottom)), + corners.bottom_left, + 90, + 180, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + bb.width - corners.bottom_right), .y = @round(bb.y + bb.height - corners.bottom_right) }, + corners.bottom_right - @as(f32, @floatFromInt(config.width.bottom)), + corners.bottom_right, + 0.1, + 90, + color, + ); }, .custom => { // Implement custom element rendering here diff --git a/examples/raylib-sidebar-container/build.zig b/examples/raylib-sidebar-container/build.zig index d29b2ea..c147d11 100644 --- a/examples/raylib-sidebar-container/build.zig +++ b/examples/raylib-sidebar-container/build.zig @@ -1,5 +1,6 @@ const std = @import("std"); const B = std.Build; +const rl = @import("raylib"); pub fn build(b: *B) void { const target = b.standardTargetOptions(.{}); @@ -10,7 +11,20 @@ pub fn build(b: *B) void { .target = target, .optimize = optimize, }); - addDependencies(root_module, b, target, optimize); + + const zclay_dep = b.dependency("zclay", .{ + .target = target, + .optimize = optimize, + }); + root_module.addImport("zclay", zclay_dep.module("zclay")); + + const raylib_dep = b.dependency("raylib_zig", .{ + .target = target, + .optimize = optimize, + .platform = .rgfw, + }); + root_module.addImport("raylib", raylib_dep.module("raylib")); + root_module.linkLibrary(raylib_dep.artifact("raylib")); { const exe = b.addExecutable(.{ .name = "zclay-example", .root_module = root_module }); @@ -42,23 +56,3 @@ pub fn build(b: *B) void { check.dependOn(&tests_check.step); } } - -fn addDependencies( - module: *B.Module, - b: *B, - target: B.ResolvedTarget, - optimize: std.builtin.OptimizeMode, -) void { - const zclay_dep = b.dependency("zclay", .{ - .target = target, - .optimize = optimize, - }); - module.addImport("zclay", zclay_dep.module("zclay")); - - const raylib_dep = b.dependency("raylib_zig", .{ - .target = target, - .optimize = optimize, - }); - module.addImport("raylib", raylib_dep.module("raylib")); - module.linkLibrary(raylib_dep.artifact("raylib")); -} diff --git a/examples/raylib-sidebar-container/build.zig.zon b/examples/raylib-sidebar-container/build.zig.zon index 698a005..82d9958 100644 --- a/examples/raylib-sidebar-container/build.zig.zon +++ b/examples/raylib-sidebar-container/build.zig.zon @@ -6,8 +6,8 @@ .path = "../../", }, .raylib_zig = .{ - .url = "git+https://github.com/Not-Nik/raylib-zig#5bbafa4f86eb3e3f41a107bbec6b8822e0f87c93", - .hash = "raylib_zig-5.6.0-dev-KE8REE0uBQD5Lzuc6qSZPtE5li3iPyU4iGQEMPqOPI11", + .url = "git+https://github.com/Not-Nik/raylib-zig#3bf08a304cfe2baf839705063ff999b8d8bc8c54", + .hash = "raylib_zig-5.6.0-dev-KE8REKAqBQAQugfCOjYYVRFOi7iaEJK1EMDcRUq8AOm2", }, }, .paths = .{ diff --git a/examples/raylib-sidebar-container/src/main.zig b/examples/raylib-sidebar-container/src/main.zig index d57ae56..bad7dd5 100644 --- a/examples/raylib-sidebar-container/src/main.zig +++ b/examples/raylib-sidebar-container/src/main.zig @@ -20,7 +20,7 @@ fn sidebarItemComponent(index: u32) void { } // An example function to begin the "root" of your layout tree -fn createLayout(profile_picture: *const rl.Texture2D) cl.ClayArray(cl.RenderCommand) { +fn createLayout(profile_picture: *const rl.Texture2D) []cl.RenderCommand { cl.beginLayout(); cl.UI()(.{ .id = .ID("OuterContainer"), @@ -46,7 +46,8 @@ fn createLayout(profile_picture: *const rl.Texture2D) cl.ClayArray(cl.RenderComm cl.UI()(.{ .id = .ID("ProfilePicture"), .layout = .{ .sizing = .{ .h = .fixed(60), .w = .fixed(60) } }, - .image = .{ .source_dimensions = .{ .h = 60, .w = 60 }, .image_data = @ptrCast(profile_picture) }, + .aspect_ratio = .{ .aspect_ratio = 60 / 60 }, + .image = .{ .image_data = @ptrCast(profile_picture) }, })({}); cl.text("Clay - UI Library", .{ .font_size = 24, .color = light_grey }); }); @@ -93,7 +94,6 @@ pub fn main() !void { .window_resizable = true, }); rl.initWindow(1000, 1000, "Raylib zig Example"); - rl.setWindowMinSize(300, 100); rl.setTargetFPS(120); // load assets @@ -124,10 +124,10 @@ pub fn main() !void { .w = @floatFromInt(rl.getScreenWidth()), .h = @floatFromInt(rl.getScreenHeight()), }); - var render_commands = createLayout(&profile_picture); + const render_commands = createLayout(&profile_picture); rl.beginDrawing(); - try renderer.clayRaylibRender(&render_commands, allocator); + try renderer.clayRaylibRender(render_commands, allocator); rl.endDrawing(); } } diff --git a/examples/raylib-sidebar-container/src/raylib_render_clay.zig b/examples/raylib-sidebar-container/src/raylib_render_clay.zig index af745e1..a89aad8 100644 --- a/examples/raylib-sidebar-container/src/raylib_render_clay.zig +++ b/examples/raylib-sidebar-container/src/raylib_render_clay.zig @@ -14,10 +14,9 @@ pub fn clayColorToRaylibColor(color: cl.Color) rl.Color { pub var raylib_fonts: [10]?rl.Font = .{null} ** 10; -pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), allocator: std.mem.Allocator) !void { - var i: usize = 0; - while (i < render_commands.length) : (i += 1) { - const render_command = cl.renderCommandArrayGet(render_commands, @intCast(i)); +pub fn clayRaylibRender(render_commands: []cl.RenderCommand, allocator: std.mem.Allocator) !void { + for (0..render_commands.len) |i| { + const render_command = render_commands[i]; const bounding_box = render_command.bounding_box; switch (render_command.command_type) { .none => {}, @@ -27,6 +26,7 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca // Raylib uses standard C strings so isn't compatible with cheap slices, we need to clone the string to append null terminator const cloned = try allocator.dupeZ(u8, text); defer allocator.free(cloned); + const fontToUse: rl.Font = raylib_fonts[config.font_id].?; rl.setTextLineSpacing(config.line_height); rl.drawTextEx( @@ -40,16 +40,18 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca }, .image => { const config = render_command.render_data.image; + var tint = config.background_color; + if (std.mem.eql(f32, &tint, &.{ 0, 0, 0, 0 })) { + tint = .{ 255, 255, 255, 255 }; + } - const image_texture: *const rl.Texture2D = @ptrCast( - @alignCast(config.image_data), - ); + const image_texture: *const rl.Texture2D = @ptrCast(@alignCast(config.image_data)); rl.drawTextureEx( image_texture.*, rl.Vector2{ .x = bounding_box.x, .y = bounding_box.y }, 0, bounding_box.width / @as(f32, @floatFromInt(image_texture.width)), - rl.Color.white, + clayColorToRaylibColor(tint), ); }, .scissor_start => { @@ -88,102 +90,90 @@ pub fn clayRaylibRender(render_commands: *cl.ClayArray(cl.RenderCommand), alloca }, .border => { const config = render_command.render_data.border; - // Left border - if (config.width.left > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x)), - @intFromFloat(@round(bounding_box.y + config.corner_radius.top_left)), - @intCast(config.width.left), - @intFromFloat(@round(bounding_box.height - config.corner_radius.top_left - config.corner_radius.bottom_left)), - clayColorToRaylibColor(config.color), - ); - } - // Right border - if (config.width.right > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + bounding_box.width - @as(f32, @floatFromInt(config.width.right)))), - @intFromFloat(@round(bounding_box.y + config.corner_radius.top_right)), - @intCast(config.width.right), - @intFromFloat(@round(bounding_box.height - config.corner_radius.top_right - config.corner_radius.bottom_right)), - clayColorToRaylibColor(config.color), - ); - } - // Top border - if (config.width.top > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + config.corner_radius.top_left)), - @intFromFloat(@round(bounding_box.y)), - @intFromFloat(@round(bounding_box.width - config.corner_radius.top_left - config.corner_radius.top_right)), - @intCast(config.width.top), - clayColorToRaylibColor(config.color), - ); - } - // Bottom border - if (config.width.bottom > 0) { - rl.drawRectangle( - @intFromFloat(@round(bounding_box.x + config.corner_radius.bottom_left)), - @intFromFloat(@round(bounding_box.y + bounding_box.height - @as(f32, @floatFromInt(config.width.bottom)))), - @intFromFloat(@round(bounding_box.width - config.corner_radius.bottom_left - config.corner_radius.bottom_right)), - @intCast(config.width.bottom), - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.top_left > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + config.corner_radius.top_left), - .y = @round(bounding_box.y + config.corner_radius.top_left), - }, - @round(config.corner_radius.top_left - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.top_left, - 180, - 270, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.top_right > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + bounding_box.width - config.corner_radius.top_right), - .y = @round(bounding_box.y + config.corner_radius.top_right), - }, - @round(config.corner_radius.top_right - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.top_right, - 270, - 360, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.bottom_left > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + config.corner_radius.bottom_left), - .y = @round(bounding_box.y + bounding_box.height - config.corner_radius.bottom_left), - }, - @round(config.corner_radius.bottom_left - @as(f32, @floatFromInt(config.width.top))), - config.corner_radius.bottom_left, - 90, - 180, - 10, - clayColorToRaylibColor(config.color), - ); - } - if (config.corner_radius.bottom_right > 0) { - rl.drawRing( - rl.Vector2{ - .x = @round(bounding_box.x + bounding_box.width - config.corner_radius.bottom_right), - .y = @round(bounding_box.y + bounding_box.height - config.corner_radius.bottom_right), - }, - @round(config.corner_radius.bottom_right - @as(f32, @floatFromInt(config.width.bottom))), - config.corner_radius.bottom_right, - 0.1, - 90, - 10, - clayColorToRaylibColor(config.color), - ); - } + const color = clayColorToRaylibColor(config.color); + const bb = bounding_box; + const corners = config.corner_radius; + + const drawRect = struct { + fn draw(x: f32, y: f32, w: f32, h: f32, c: rl.Color) void { + rl.drawRectangle(@intFromFloat(@round(x)), @intFromFloat(@round(y)), @intFromFloat(@round(w)), @intFromFloat(@round(h)), c); + } + }.draw; + + drawRect( + bb.x, + bb.y + corners.top_left, + @floatFromInt(config.width.left), + bb.height - corners.top_left - corners.bottom_left, + color, + ); + + drawRect( + bb.x + bb.width - @as(f32, @floatFromInt(config.width.right)), + bb.y + corners.top_right, + @floatFromInt(config.width.right), + bb.height - corners.top_right - corners.bottom_right, + color, + ); + + drawRect( + bb.x + corners.top_left, + bb.y, + bb.width - corners.top_left - corners.top_right, + @floatFromInt(config.width.top), + color, + ); + + drawRect( + bb.x + corners.bottom_left, + bb.y + bb.height - @as(f32, @floatFromInt(config.width.bottom)), + bb.width - corners.bottom_left - corners.bottom_right, + @floatFromInt(config.width.bottom), + color, + ); + + const drawCorner = struct { + fn draw(center: rl.Vector2, innerRadius: f32, outerRadius: f32, startAngle: f32, endAngle: f32, c: rl.Color) void { + if (outerRadius <= 0) return; + rl.drawRing(center, @round(innerRadius), @round(outerRadius), startAngle, endAngle, 10, c); + } + }.draw; + + drawCorner( + rl.Vector2{ .x = @round(bb.x + corners.top_left), .y = @round(bb.y + corners.top_left) }, + corners.top_left - @as(f32, @floatFromInt(config.width.top)), + corners.top_left, + 180, + 270, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + bb.width - corners.top_right), .y = @round(bb.y + corners.top_right) }, + corners.top_right - @as(f32, @floatFromInt(config.width.top)), + corners.top_right, + 270, + 360, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + corners.bottom_left), .y = @round(bb.y + bb.height - corners.bottom_left) }, + corners.bottom_left - @as(f32, @floatFromInt(config.width.bottom)), + corners.bottom_left, + 90, + 180, + color, + ); + + drawCorner( + rl.Vector2{ .x = @round(bb.x + bb.width - corners.bottom_right), .y = @round(bb.y + bb.height - corners.bottom_right) }, + corners.bottom_right - @as(f32, @floatFromInt(config.width.bottom)), + corners.bottom_right, + 0.1, + 90, + color, + ); }, .custom => { // Implement custom element rendering here diff --git a/src/root.zig b/src/root.zig index a55b2e4..42fe20c 100644 --- a/src/root.zig +++ b/src/root.zig @@ -13,23 +13,25 @@ pub extern var Clay__debugViewWidth: u32; pub const cdefs = struct { pub extern fn Clay_GetElementData(id: ElementId) ElementData; pub extern fn Clay_MinMemorySize() u32; - pub extern fn Clay_CreateArenaWithCapacityAndMemory(capacity: u32, memory: ?*anyopaque) Arena; + pub extern fn Clay_CreateArenaWithCapacityAndMemory(capacity: usize, memory: ?*anyopaque) Arena; pub extern fn Clay_SetPointerState(position: Vector2, pointerDown: bool) void; pub extern fn Clay_Initialize(arena: Arena, layoutDimensions: Dimensions, errorHandler: ErrorHandler) *Context; pub extern fn Clay_GetCurrentContext() *Context; pub extern fn Clay_SetCurrentContext(context: *Context) void; pub extern fn Clay_UpdateScrollContainers(enableDragScrolling: bool, scrollDelta: Vector2, deltaTime: f32) void; + pub extern fn Clay_GetScrollOffset() Vector2; pub extern fn Clay_SetLayoutDimensions(dimensions: Dimensions) void; pub extern fn Clay_BeginLayout() void; pub extern fn Clay_EndLayout() ClayArray(RenderCommand); pub extern fn Clay_GetElementId(idString: String) ElementId; pub extern fn Clay_GetElementIdWithIndex(idString: String, index: u32) ElementId; pub extern fn Clay_Hovered() bool; - pub extern fn Clay_OnHover(onHoverFunction: *const fn (ElementId, PointerData, ?*anyopaque) callconv(.c) void, userData: ?*anyopaque) void; + pub extern fn Clay_OnHover(onHoverFunction: *const fn (ElementId, PointerData, ?*anyopaque) callconv(.c) void, user_data: ?*anyopaque) void; pub extern fn Clay_PointerOver(elementId: ElementId) bool; + pub extern fn Clay_GetPointerOverIds() ClayArray(ElementId); pub extern fn Clay_GetScrollContainerData(id: ElementId) ScrollContainerData; - pub extern fn Clay_SetMeasureTextFunction(measureTextFunction: *const fn (StringSlice, *TextElementConfig, ?*anyopaque) callconv(.c) Dimensions, userData: ?*anyopaque) void; - pub extern fn Clay_SetQueryScrollOffsetFunction(queryScrollOffsetFunction: *const fn (u32, ?*anyopaque) callconv(.c) Vector2, userData: ?*anyopaque) void; + pub extern fn Clay_SetMeasureTextFunction(measureTextFunction: *const fn (StringSlice, *TextElementConfig, ?*anyopaque) callconv(.c) Dimensions, user_data: ?*anyopaque) void; + pub extern fn Clay_SetQueryScrollOffsetFunction(queryScrollOffsetFunction: *const fn (u32, ?*anyopaque) callconv(.c) Vector2, user_data: ?*anyopaque) void; pub extern fn Clay_RenderCommandArray_Get(array: *ClayArray(RenderCommand), index: i32) *RenderCommand; pub extern fn Clay_SetDebugModeEnabled(enabled: bool) void; pub extern fn Clay_IsDebugModeEnabled() bool; @@ -41,6 +43,7 @@ pub const cdefs = struct { pub extern fn Clay_ResetMeasureTextCache() void; pub extern fn Clay__ConfigureOpenElement(config: ElementDeclaration) void; + pub extern fn Clay__ConfigureOpenElementPtr(config: *ElementDeclaration) void; // TODO: investigate uses pub extern fn Clay__OpenElement() void; pub extern fn Clay__CloseElement() void; pub extern fn Clay__StoreTextElementConfig(config: TextElementConfig) *TextElementConfig; @@ -53,6 +56,8 @@ pub const EnumBackingType = u8; /// Clay String representation, not guaranteed to be null terminated pub const String = extern struct { + // TODO: doc + is_statically_allocated: bool = false, /// Length of the string in bytes length: i32, /// Pointer to the character data @@ -84,7 +89,7 @@ pub const Context = opaque {}; /// Create using createArenaWithCapacityAndMemory() instead of manually pub const Arena = extern struct { /// Pointer to the next allocation (internal use) - nextAllocation: usize, + next_allocation: usize, /// Total capacity of the arena in bytes capacity: usize, /// Pointer to the arena's memory @@ -242,6 +247,8 @@ pub const TextAlignment = enum(EnumBackingType) { }; pub const TextElementConfig = extern struct { + // TODO: doc + user_data: ?*anyopaque = null, /// The RGBA color of the font to render, conventionally specified as 0-255. color: Color = .{ 0, 0, 0, 255 }, /// An integer transparently passed to Clay_MeasureText to identify the font to use. @@ -257,10 +264,6 @@ pub const TextElementConfig = extern struct { wrap_mode: TextElementConfigWrapMode = .words, /// Controls how wrapped lines of text are horizontally aligned within the outer text bounding box. alignement: TextAlignment = .left, - /// When set to true, clay will hash the entire text contents of this string as an identifier for its internal - /// text measurement cache, rather than just the pointer and length. This will incur significant performance cost for - /// long bodies of text. - hash_string_contents: bool = false, }; pub const FloatingAttachPointType = enum(EnumBackingType) { @@ -293,6 +296,13 @@ pub const FloatingAttachToElement = enum(EnumBackingType) { to_root = 3, }; +pub const FloatingClipToElement = enum(EnumBackingType) { + // TODO: doc + to_none = 0, + // TODO: doc + to_attached_parent = 1, +}; + /// Controls how pointer events are handled by floating elements pub const PointerCaptureMode = enum(EnumBackingType) { /// (default) Captures pointer events and doesn't pass through to elements underneath @@ -309,13 +319,15 @@ pub const FloatingElementConfig = extern struct { /// When using CLAY_ATTACH_TO_ELEMENT_WITH_ID, attaches to element with this ID parentId: u32 = 0, /// Z-index controls stacking order (ascending) - zIndex: i16 = 0, + z_index: i16 = 0, /// Controls attachment points between floating element and its parent attach_points: FloatingAttachPoints = .{ .element = .left_top, .parent = .left_top }, /// Controls whether pointer events are captured or pass through to elements underneath pointer_capture_mode: PointerCaptureMode = .capture, /// Controls which element this floating element is attached to attach_to: FloatingAttachToElement = .to_none, + // TODO: doc + clip_to: FloatingClipToElement = .to_none, }; pub const RenderCommandType = enum(EnumBackingType) { @@ -518,9 +530,9 @@ pub const LayoutConfig = extern struct { pub fn ClayArray(comptime T: type) type { return extern struct { /// Maximum capacity of the array (not all elements may be initialized) - capacity: u32, + capacity: i32, /// Number of initialized elements in the array - length: u32, + length: i32, /// Pointer to the first element in the array internal_array: [*]T, }; @@ -595,8 +607,6 @@ pub const ImageRenderData = extern struct { background_color: Color, /// Corner rounding for the image corner_radius: CornerRadius, - /// Original dimensions of the source image - source_dimensions: Dimensions, /// Transparent pointer to image data image_data: ?*anyopaque, }; @@ -610,15 +620,18 @@ pub const CustomRenderData = extern struct { custom_data: ?*anyopaque, }; +pub const AspectRatioElementConfig = extern struct { + // TODO: doc + aspect_ratio: f32 = 0, +}; + pub const ImageElementConfig = extern struct { /// Transparent pointer to image data image_data: ?*const anyopaque, - /// Original dimensions of the source image - source_dimensions: Dimensions, }; /// Render command data for scissor (clipping) commands -pub const ScrollRenderData = extern struct { +pub const ClipRenderData = extern struct { /// Whether to clip/scroll horizontally horizontal: bool, /// Whether to clip/scroll vertically @@ -640,7 +653,7 @@ pub const RenderData = extern union { image: ImageRenderData, custom: CustomRenderData, border: BorderRenderData, - scroll: ScrollRenderData, + scroll: ClipRenderData, }; /// Configuration for custom elements @@ -659,7 +672,7 @@ pub const ScrollContainerData = extern struct { /// Dimensions of the inner content, including parent padding content_dimensions: Dimensions, /// Original scroll config - config: ScrollElementConfig, + config: ClipElementConfig, /// Whether a scroll container was found with the provided ID found: bool, }; @@ -673,21 +686,23 @@ pub const ElementData = extern struct { }; /// Controls the axes on which an element can scroll -pub const ScrollElementConfig = extern struct { +pub const ClipElementConfig = extern struct { /// Whether to enable horizontal scrolling horizontal: bool = false, /// Whether to enable vertical scrolling vertical: bool = false, + // TODO: doc + child_offset: Vector2 = .{ .x = 0, .y = 0 }, }; /// Shared configuration properties for multiple element types pub const SharedElementConfig = extern struct { /// Background color of the element - backgroundColor: Color, + background_color: Color, /// Corner rounding of the element - cornerRadius: CornerRadius, + corner_radius: CornerRadius, /// Transparent pointer passed to render commands - userData: ?*anyopaque, + user_data: ?*anyopaque, }; /// Element configuration type identifiers @@ -708,24 +723,26 @@ pub const ElementDeclaration = extern struct { /// Firstly, tagging an element with an ID allows you to query information about the element later, such as its mouseover state or dimensions. /// /// Secondly, IDs are visually useful when attempting to read and modify UI code, as well as when using the built-in debug tools. - id: ElementId = .{ .base_id = 0, .id = 0, .offset = 0, .string_id = .{ .chars = undefined, .length = 0 } }, + id: ElementId = .{ .base_id = 0, .id = 0, .offset = 0, .string_id = .{ .chars = &.{}, .length = 0 } }, /// Controls various settings that affect the size and position of an element, as well as the sizes and positions of any child elements. layout: LayoutConfig = .{}, /// Controls the background color of the resulting element. /// By convention specified as 0-255, but interpretation is up to the renderer. - /// If no other config is specified, .backgroundColor will generate a RECTANGLE render command, otherwise it will be passed as a property to IMAGE or CUSTOM render commands. + /// If no other config is specified, .background_color will generate a RECTANGLE render command, otherwise it will be passed as a property to IMAGE or CUSTOM render commands. background_color: Color = .{ 0, 0, 0, 0 }, /// Controls the "radius", or corner rounding of elements, including rectangles, borders and images. corner_radius: CornerRadius = .{}, + // TODO: doc + aspect_ratio: AspectRatioElementConfig = .{}, /// Controls settings related to image elements. - image: ImageElementConfig = .{ .image_data = null, .source_dimensions = .{ .h = 0, .w = 0 } }, + image: ImageElementConfig = .{ .image_data = null }, /// Controls whether and how an element "floats", which means it layers over the top of other elements in z order, and doesn't affect the position and size of siblings or parent elements. /// Note: in order to activate floating, .floating.attachTo must be set to something other than the default value. floating: FloatingElementConfig = .{}, /// Used to create CUSTOM render commands, usually to render element types not supported by Clay. custom: CustomElementConfig = .{}, /// Controls whether an element should clip its contents and allow scrolling rather than expanding to contain them. - scroll: ScrollElementConfig = .{}, + clip: ClipElementConfig = .{}, /// Controls settings related to element borders, and will generate BORDER render command border: BorderElementConfig = .{}, /// A pointer that will be transparently passed through to resulting render command @@ -839,7 +856,10 @@ pub const beginLayout = cdefs.Clay_BeginLayout; /// const commands = endLayout(); /// // Now render the commands with your graphics API /// ``` -pub const endLayout = cdefs.Clay_EndLayout; +pub fn endLayout() []RenderCommand { + const commands = cdefs.Clay_EndLayout(); + return commands.internal_array[0..@intCast(commands.length)]; +} /// Gets an element ID with a numeric index - useful for loops /// Generally only used for dynamic strings when ElementId.IDI() can't be used @@ -1062,6 +1082,17 @@ pub fn getElementId(string: []const u8) ElementId { return cdefs.Clay_GetElementId(.fromSlice(string)); } +// TODO: doc +fn getScrollOffset() Vector2 { + return cdefs.Clay_GetScrollOffset(); +} + +// TODO: doc +fn getPointerOverIds() []ElementId { + const ids = cdefs.Clay_GetPointerOverIds(); + return ids.internal_array[0..@intCast(ids.length)]; +} + fn anytypeToAnyopaquePtr(user_data: anytype) ?*anyopaque { if (@TypeOf(user_data) == void) { return null; @@ -1072,12 +1103,12 @@ fn anytypeToAnyopaquePtr(user_data: anytype) ?*anyopaque { } } -fn anyopaquePtrToAnytype(T: type, userData: ?*anyopaque) T { +fn anyopaquePtrToAnytype(T: type, user_data: ?*anyopaque) T { if (T == void) { return {}; } else if (@typeInfo(T) == .pointer) { - return @ptrCast(@alignCast(@constCast(userData))); + return @ptrCast(@alignCast(@constCast(user_data))); } else { - return @bitCast(@as(usize, @intFromPtr(userData))); + return @bitCast(@as(usize, @intFromPtr(user_data))); } }