diff --git a/bindings/jai/clay-jai/windows/clay.lib b/bindings/jai/clay-jai/windows/clay.lib index 734b752..90974cd 100644 Binary files a/bindings/jai/clay-jai/windows/clay.lib and b/bindings/jai/clay-jai/windows/clay.lib differ 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";