From 672927d387a861a6825654546e04d97d1f00614a Mon Sep 17 00:00:00 2001
From: Stowy <stowy@protonmail.ch>
Date: Thu, 2 Jan 2025 23:19:31 +0100
Subject: [PATCH] Finished first version of the bindings with working demo !!

---
 bindings/jai/clay-jai/windows/clay.lib        | Bin 294086 -> 294086 bytes
 .../clay_renderer_raylib.jai                  |  24 ++-
 .../introducing_clay_video_demo/main.jai      | 202 ++++++++++++++++--
 .../introducing_clay_video_demo/test.jai      |  21 --
 bindings/jai/generate.jai                     |   6 +-
 bindings/jai/module.jai                       |  62 +++---
 bindings/jai/windows.jai                      |   5 +-
 7 files changed, 236 insertions(+), 84 deletions(-)
 delete mode 100644 bindings/jai/examples/introducing_clay_video_demo/test.jai

diff --git a/bindings/jai/clay-jai/windows/clay.lib b/bindings/jai/clay-jai/windows/clay.lib
index 734b752702e11adb1aebd1dd37cdaec1d52cadc6..90974cd6236673c7672f0697d4c02e5bffd640de 100644
GIT binary patch
delta 34
ncmX^1Q}EbN!3~=Vne({Ho3|FWZ!Kg5VkRJF-oCYvMUWc+C-V;(

delta 34
ncmX^1Q}EbN!3~=VnR)z6nzt6VZ!Kg5VkRJF-oCYvMUWc+B(x6s

diff --git a/bindings/jai/examples/introducing_clay_video_demo/clay_renderer_raylib.jai b/bindings/jai/examples/introducing_clay_video_demo/clay_renderer_raylib.jai
index 439fc47..efed716 100644
--- a/bindings/jai/examples/introducing_clay_video_demo/clay_renderer_raylib.jai
+++ b/bindings/jai/examples/introducing_clay_video_demo/clay_renderer_raylib.jai
@@ -19,18 +19,20 @@ raylib_measure_text :: (text: *Clay.String, config: *Clay.TextElementConfig) ->
 	text_height := cast(float)config.fontSize;
 	font_to_use := g_raylib_fonts[config.fontId].font;
 
-	for 0..text.length - 1 {
-		if text.chars[it] == #char "\n" {
-			max_text_width = c_max(max_text_width, line_text_width);
-			line_text_width = 0;
-			continue;
-		}
+	if text.length > 0 {
+		for 0..(text.length - 1) {
+			if text.chars[it] == #char "\n" {
+				max_text_width = c_max(max_text_width, line_text_width);
+				line_text_width = 0;
+				continue;
+			}
 
-		index := cast(s32) text.chars[it] - 32;
-		if font_to_use.glyphs[index].advanceX != 0 {
-			line_text_width += cast(float) font_to_use.glyphs[index].advanceX;
-		} else {
-			line_text_width += (font_to_use.recs[index].width + cast(float) font_to_use.glyphs[index].offsetX);
+			index := cast(s32, text.chars[it]) - 32;
+			if font_to_use.glyphs[index].advanceX != 0 {
+				line_text_width += cast(float) font_to_use.glyphs[index].advanceX;
+			} else {
+				line_text_width += (font_to_use.recs[index].width + cast(float) font_to_use.glyphs[index].offsetX);
+			}
 		}
 	}
 
diff --git a/bindings/jai/examples/introducing_clay_video_demo/main.jai b/bindings/jai/examples/introducing_clay_video_demo/main.jai
index d711f7a..35689c5 100644
--- a/bindings/jai/examples/introducing_clay_video_demo/main.jai
+++ b/bindings/jai/examples/introducing_clay_video_demo/main.jai
@@ -3,6 +3,8 @@ using Basic :: #import "Basic";
 Clay :: #import,file "../../module.jai";
 Raylib :: #import "raylib-jai";
 
+for_expansion :: Clay.for_expansion;;
+
 #load "clay_renderer_raylib.jai";
 
 FONT_ID_BODY_16 :: 0;
@@ -28,14 +30,60 @@ to_jai_string :: (str: Clay.String) -> string {
     return .{data = str.chars, count = cast(s64, str.length)};
 }
 
+// handle_sidebar_interaction :: (
+//     element_id: Clay.ElementId,
+//     pointer_data: Clay.PointerData,
+//     user_data: s64
+// ) #c_call {
+//     // If this button was clicked
+//     if pointer_data.state == .PRESSED_THIS_FRAME {
+//         selected_document_index = user_data;
+//     }
+// }
+
 handle_clay_errors :: (error_data: Clay.ErrorData) #c_call {
     push_context {
-        log_error("Clay Error : %", to_jai_string(error_data.errorText));
+        log_error(
+            "Clay Error [%]: % | %", 
+            error_data.errorType, 
+            to_jai_string(error_data.errorText),
+            error_data.userData
+        );
     }
 }
 
+render_header_button :: (text: string) {
+    for Clay.Element(
+        Clay.Layout(.{padding = .{16, 8}}),
+        Clay.Rectangle(.{
+            color = .{140, 140, 140, 255},
+            cornerRadius = .{5, 5, 5, 5},
+        })
+    ) {
+        Clay.Text(text, Clay.TextConfig(.{
+            fontId = FONT_ID_BODY_16,
+            fontSize = 16,
+            textColor = COLOR_WHITE,
+        }));
+    }
+}
+
+render_dropdown_menu_item :: (text: string) {
+    for Clay.Element(
+        Clay.Layout(.{padding = .{16, 16}})
+    ) {
+        Clay.Text(text, Clay.TextConfig(.{
+            fontId = FONT_ID_BODY_16,
+            fontSize = 16,
+            textColor = COLOR_WHITE,
+        }));
+    }
+}
+
+selected_document_index : int = 0;
+
 main :: () {
-    flags := Raylib.ConfigFlags.WINDOW_RESIZABLE | .WINDOW_HIGHDPI | .MSAA_4X_HINT | .VSYNC_HINT;
+    flags := Raylib.ConfigFlags.WINDOW_RESIZABLE | .MSAA_4X_HINT | .VSYNC_HINT;
     raylib_initialize(1024, 768, "Introducing Clay Demo", flags);
 
     clay_required_memory := Clay.MinMemorySize();
@@ -76,7 +124,7 @@ main :: () {
         };
 
         Clay.BeginLayout();
-        Clay.UI(
+        for Clay.Element(
             Clay.ID("OuterContainer"),
             Clay.Rectangle(.{color = .{43, 41, 51, 255}}),
             Clay.Layout(.{
@@ -85,8 +133,8 @@ main :: () {
                 padding = .{16, 16},
                 childGap = 16,
             }),
-            children = #code {
-            Clay.UI(
+        ) {
+            for Clay.Element(
                 Clay.ID("HeaderBar"),
                 Clay.Rectangle(content_background_config),
                 Clay.Layout(.{
@@ -100,33 +148,148 @@ main :: () {
                         y = .CENTER,
                     }
                 }),
-                children = #code {
-                Clay.UI(
+            ) {
+                for Clay.Element(
                     Clay.ID("FileButton"),
                     Clay.Layout(.{padding = .{16, 8}}),
                     Clay.Rectangle(.{
                         color = .{140, 140, 140, 255},
                         cornerRadius = .{5, 5, 5, 5},
                     }),
-                    children = #code {
+                ) {
                     Clay.Text("File", Clay.TextConfig(.{
-                            fontId = FONT_ID_BODY_16,
-                            fontSize = 16,
-                            textColor = Clay.Color.{255, 255, 255, 255},
+                        fontId = FONT_ID_BODY_16,
+                        fontSize = 16,
+                        textColor = COLOR_WHITE,
                     }));
 
                     file_menu_visible := Clay.PointerOver(Clay.GetElementId("FileButton")) ||
-                        Clay.PointerOver(Clay.GetElementId("FileMenu"));
-                    
+                    Clay.PointerOver(Clay.GetElementId("FileMenu"));
+
                     if file_menu_visible {
-                        
+                        for Clay.Element(
+                            Clay.ID("FileMenu"),
+                            Clay.Floating(.{attachment = .{parent = .LEFT_BOTTOM}}),
+                            Clay.Layout(.{padding = .{0, 8}})
+                        ) {
+                            for Clay.Element(
+                                Clay.Layout(.{
+                                    layoutDirection=.TOP_TO_BOTTOM,
+                                    sizing = .{width = Clay.SizingFixed(200)}
+                                }),
+                                Clay.Rectangle(.{
+                                    color = .{40, 40, 40, 255},
+                                    cornerRadius = .{8, 8, 8, 8}
+                                })
+                            ) {
+                                // Render dropdown items here
+                                render_dropdown_menu_item("New");
+                                render_dropdown_menu_item("Open");
+                                render_dropdown_menu_item("Close");
+                            }
+                        }
                     }
-                    }
-                );
                 }
-            );
+
+                // Render header buttons
+                render_header_button("Edit");
+                for Clay.Element(Clay.Layout(.{
+                    sizing = .{Clay.SizingGrow(), Clay.SizingGrow()}})) {}
+                render_header_button("Upload");
+                render_header_button("Media");
+                render_header_button("Support");
             }
-        );
+
+            for Clay.Element(
+                Clay.ID("LowerContent"),
+                Clay.Layout(.{sizing = layout_expand, childGap = 16}),
+            ) {
+                for Clay.Element(
+                    Clay.ID("Sidebar"),
+                    Clay.Rectangle(content_background_config),
+                    Clay.Layout(.{
+                        layoutDirection = .TOP_TO_BOTTOM,
+                        padding = .{16, 16},
+                        childGap = 8,
+                        sizing = .{
+                            width = Clay.SizingFixed(250),
+                            height = Clay.SizingGrow(),
+                        }
+                    })
+                ) {
+                    for document : documents {
+                        sidebar_button_layout := Clay.LayoutConfig.{
+                            sizing = .{width = Clay.SizingGrow()},
+                            padding = .{16, 16},
+                        };
+
+                        if it_index == selected_document_index {
+                            for Clay.Element(
+                                Clay.Layout(sidebar_button_layout),
+                                Clay.Rectangle(.{
+                                    color = .{120, 120, 120, 255},
+                                    cornerRadius = .{8, 8, 8, 8},
+                                })
+                            ) {
+                                Clay.Text(document.title, Clay.TextConfig(.{
+                                    fontId = FONT_ID_BODY_16,
+                                    fontSize = 20,
+                                    textColor = COLOR_WHITE,
+                                }));
+                            }
+                        } else {
+                            id := tprint("Parnets %", it_index);
+                            is_hovered := Clay.PointerOver(Clay.GetElementId(id));
+                            if is_hovered && Raylib.IsMouseButtonPressed(0) {
+                                selected_document_index = it_index;
+                            }
+
+                            for Clay.Element(
+                                Clay.ID(id)
+                            ) {
+                                for Clay.Element(
+                                    Clay.Layout(sidebar_button_layout),
+                                    ifx is_hovered then Clay.Rectangle(.{
+                                        color = .{120, 120, 120, 120},
+                                        cornerRadius = .{8, 8, 8, 8},
+                                    }) else .{}
+                                ) {
+                                    Clay.Text(document.title, Clay.TextConfig(.{
+                                        fontId = FONT_ID_BODY_16,
+                                        fontSize = 20,
+                                        textColor = COLOR_WHITE
+                                    }));
+                                }
+                            }
+                        }
+                    }
+                }
+
+                for Clay.Element(
+                    Clay.ID("MainContent"),
+                    Clay.Rectangle(content_background_config),
+                    Clay.Scroll(.{vertical = true}),
+                    Clay.Layout(.{
+                        layoutDirection = .TOP_TO_BOTTOM,
+                        childGap = 16,
+                        padding = .{16, 16},
+                        sizing = layout_expand,
+                    }),
+                ) {
+                    selected_document := documents[selected_document_index];
+                    Clay.Text(selected_document.title, Clay.TextConfig(.{
+                        fontId = FONT_ID_BODY_16,
+                        fontSize = 24,
+                        textColor = COLOR_WHITE,
+                    }));
+                    Clay.Text(selected_document.contents, Clay.TextConfig(.{
+                        fontId = FONT_ID_BODY_16,
+                        fontSize = 24,
+                        textColor = COLOR_WHITE
+                    }));
+                }
+            }
+        }
 
         render_commands := Clay.EndLayout();
 
@@ -134,6 +297,7 @@ main :: () {
         Raylib.ClearBackground(Raylib.BLACK);
         clay_raylib_render(render_commands);
         Raylib.EndDrawing();
-    }
 
+        reset_temporary_storage();
+    }
 }
\ No newline at end of file
diff --git a/bindings/jai/examples/introducing_clay_video_demo/test.jai b/bindings/jai/examples/introducing_clay_video_demo/test.jai
deleted file mode 100644
index 44c4809..0000000
--- a/bindings/jai/examples/introducing_clay_video_demo/test.jai
+++ /dev/null
@@ -1,21 +0,0 @@
-#import "Basic";
-
-
-test :: () -> bool #must #expand {
-	print("one\n");
-	
-	`defer print("two\n");
-
-	return true;
-}
-
-main :: () {
-	print("ichi\n");
-	if test() {
-		print("ni\n");
-		if test() {
-			print("san\n");
-		}
-	}
-	print("yon\n");
-}
\ No newline at end of file
diff --git a/bindings/jai/generate.jai b/bindings/jai/generate.jai
index 71e21c6..a9e6599 100644
--- a/bindings/jai/generate.jai
+++ b/bindings/jai/generate.jai
@@ -2,11 +2,15 @@ AT_COMPILE_TIME :: true;
 
 SOURCE_PATH :: "source";
 
-// These have custom declaration in module.jai
 DECLARATIONS_TO_OMIT :: string.[
+    // These have custom declaration in module.jai
     "Clay_Vector2",
     "Clay__ElementConfigType",
     "Clay__AlignClay__ElementConfigType",
+
+    // These are not supported yet
+    "Clay_OnHover",
+    "Clay_Hovered",
 ];
 
 #if AT_COMPILE_TIME {
diff --git a/bindings/jai/module.jai b/bindings/jai/module.jai
index 1acb1b8..2ee5b52 100644
--- a/bindings/jai/module.jai
+++ b/bindings/jai/module.jai
@@ -34,13 +34,19 @@ TypedConfig :: struct {
 }
 
 make_string :: (str: string) -> String {
-    return .{cast(u64, str.count), str.data};
+    clay_string := String.{cast(u64, str.count), str.data};
+    return clay_string;
 }
 
-// The way of handling this is inspired by the odin bindings
-UI :: (configs: ..TypedConfig, $children: Code = #code {}, $call := #caller_code) {
+global_counter := 0;
+
+for_expansion :: (configs_array: InternalElementConfigArray, body: Code, _: For_Flags) #expand {
+    // Jai forces the definition of these
+    `it_index := 0;
+    `it := 0;
+
     _OpenElement();
-    for config : configs {
+    for config : configs_array.configs {
         if config.type == {
         case .ID;
             _AttachId(config.id);
@@ -56,35 +62,14 @@ UI :: (configs: ..TypedConfig, $children: Code = #code {}, $call := #caller_code
     }
     _ElementPostConfiguration();
 
-    #insert,scope(call) children;
+    #insert body;
 
     _CloseElement();
 }
 
-// Not sure yet wich of these two methods is better
-// Idealy there should be a way to mimic the style of how it's done in C
-// ElementScope :: (configs: ..TypedConfig) #expand {
-//     _OpenElement();
-//     for config : configs {
-//         if config.type == {
-//         case .ID;
-//             _AttachId(config.id);
-//         case .LAYOUT;
-//             _AttachLayoutConfig(cast(*LayoutConfig, config.config));
-//         case;
-//             // config.config is a *void, it stores the address of the pointer that is stored in the union
-//             // as ElementConfigUnion is a union of structs. We can't cast pointers directly to structs,
-//             // we first cast the address of the *void and then dereference it.
-//             // Maybe there's a cast modifier to avoid this, but I don't know it (no_check and trunc didn't work).
-//             _AttachElementConfig(cast(*ElementConfigUnion, *config.config).*, config.type);
-//         }
-//     }
-//     _ElementPostConfiguration();
-
-//     `defer _CloseElement();
-// }
-
-
+Element :: (configs: ..TypedConfig) -> InternalElementConfigArray #expand {
+    return .{configs};
+}
 
 ID :: (label: string, index: u32 = 0) -> TypedConfig {
     return .{type = .ID, id = _HashString(make_string(label), index, 0)};
@@ -101,6 +86,14 @@ Rectangle :: (config: RectangleElementConfig) -> TypedConfig {
     };
 }
 
+Floating :: (config: FloatingElementConfig) -> TypedConfig {
+    return .{type = .FLOATING_CONTAINER, config = _StoreFloatingElementConfig(config)};
+}
+
+Scroll :: (config: ScrollElementConfig) -> TypedConfig {
+    return .{type = .SCROLL_CONTAINER, config = _StoreScrollElementConfig(config)};
+}
+
 Text :: (text: string, config: *TextElementConfig) {
     _OpenTextElement(make_string(text), config);
 }
@@ -121,12 +114,23 @@ GetElementId :: (str: string) -> ElementId {
     return GetElementId(make_string(str));
 }
 
+// OnHover :: (onHoverFunction: #type (elementId: ElementId, pointerData: PointerData, userData: s64) -> void #c_call, userData: s64) -> TypedConfig {
+//     OnHover(onHoverFunction, userData);
+//     return TypedConfig.{
+//         type = .NONE,
+//     };
+// }
+
 #scope_module
 
 Math :: #import "Math";
 Compiler :: #import "Compiler";
 ProgramPrint :: #import "Program_Print";
 
+InternalElementConfigArray :: struct {
+    configs: [] TypedConfig;
+}
+
 #if OS == .WINDOWS {
     #load "windows.jai";
 } else {
diff --git a/bindings/jai/windows.jai b/bindings/jai/windows.jai
index d3ad1e5..5d20671 100644
--- a/bindings/jai/windows.jai
+++ b/bindings/jai/windows.jai
@@ -1,7 +1,7 @@
 //
 // This file was auto-generated using the following command:
 //
-// jai generate.jai - -compile
+// jai ./generate.jai - -compile
 //
 
 
@@ -551,8 +551,7 @@ BeginLayout :: () -> void #foreign clay "Clay_BeginLayout";
 EndLayout :: () -> RenderCommandArray #foreign clay "Clay_EndLayout";
 GetElementId :: (idString: String) -> ElementId #foreign clay "Clay_GetElementId";
 GetElementIdWithIndex :: (idString: String, index: u32) -> ElementId #foreign clay "Clay_GetElementIdWithIndex";
-Hovered :: () -> bool #foreign clay "Clay_Hovered";
-OnHover :: (onHoverFunction: #type (elementId: ElementId, pointerData: PointerData, userData: s64) -> void #c_call, userData: s64) -> void #foreign clay "Clay_OnHover";
+
 PointerOver :: (elementId: ElementId) -> bool #foreign clay "Clay_PointerOver";
 GetScrollContainerData :: (id: ElementId) -> ScrollContainerData #foreign clay "Clay_GetScrollContainerData";
 SetMeasureTextFunction :: (measureTextFunction: #type (text: *String, config: *TextElementConfig) -> Dimensions #c_call) -> void #foreign clay "Clay_SetMeasureTextFunction";