const std = @import("std"); const rl = @import("rl"); const shoots = @import("shoots"); fn getTextWidth(string: []const u8, font: rl.Font) shoots.Real { var width: c_int = 0; for (string) |char| { width += @as(c_int, @intFromFloat(font.recs[char - 32].width)) + font.glyphs[char - 32].offsetX; } const s = @as([:0]const u8, @ptrCast(string)); return @as(shoots.Real, @floatFromInt(rl.measureText(s, font.baseSize))); } fn getTextheight(string: []const u8, font: rl.Font) shoots.Real { _ = string; // std.debug.print("font.baseSize : {}\n", .{font.baseSize}); return @as(shoots.Real, @floatFromInt(font.baseSize)); } const TextType = shoots.TextType(rl.Font, getTextWidth, getTextheight); const TextureType = shoots.TextureType(rl.Texture2D); const UI = shoots.Shoots(TextType, TextureType); inline fn sideBar() UI.Node { return UI.Element(.{ .name = "sidebar", .rect = .{ .h = 20, .w = 40, }, .style = .{ .background_colour = .{ .r = 255, .b = 255, }, .size_y = .grow, // .size_x = .grow, }, }); } fn updateButton(element: *UI.Ele, mouse_data: shoots.MouseState, user_data: *anyopaque) bool { _ = user_data; if (mouse_data.left) { std.debug.print("button pressed\n", .{}); element.style.background_colour = .{ .b = 255, .g = 255 }; } return false; } fn hoverButton(element: *UI.Ele, mouse_data: shoots.MouseState, user_data: *anyopaque) bool { _ = user_data; _ = mouse_data; element.style.background_colour = .{ .b = 128, .g = 128 }; return false; } inline fn button() UI.Node { return UI.ElementWborder( .{ .bottom = 2, .left = 2, .right = 2, .top = 2, }, .{ .b = 30, }, .{ .name = "button", .rect = .{ .h = 20, .w = 60, }, .on_click = .{ .func = &updateButton, .data = &.{}, }, .on_hover = .{ .func = &hoverButton, .data = &.{}, }, .style = .{ .background_colour = .{ .g = 255, }, .rounded = 25, }, }, ); } pub fn main() anyerror!void { // Initialization //-------------------------------------------------------------------------------------- const screenWidth = 1200; const screenHeight = 700; var timer = try std.time.Timer.start(); rl.initWindow(screenWidth, screenHeight, "raylib-zig [core] example - basic window"); defer rl.closeWindow(); // Close window and OpenGL context rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second //-------------------------------------------------------------------------------------- std.debug.print("shoots version :{s}\n", .{shoots.VERSION}); std.debug.print("raylib time : {}\n", .{@divTrunc(timer.lap(), std.time.ns_per_ms)}); const child = &[_]UI.Node{ sideBar(), button(), UI.Element(.{ .style = .{ .background_colour = .{ .b = 120, }, .padding = .{ .bottom = 10, .left = 10, .right = 10.4, .top = 10, }, }, .children = &[_]UI.Node{ UI.Txt( UI.Text.init( "hello world", try rl.getFontDefault(), .{}, ), ), UI.Txt( UI.Text.init( "hello world again", try rl.getFontDefault(), .{}, ).setBackground(.{ .a = 255, .g = 255, }), ), }, }), UI.Element(.{ .name = "child", .style = .{ .background_colour = .{ .b = 255, }, .padding = .{ .bottom = 5 } }, .children = &[_]UI.Node{ UI.Element(.{ .name = "branch1", // .rect = .{ .w = 200 }, .style = .{ .size_x = .grow, .padding = .{ .bottom = 5, .left = 5, .top = 5, .right = 5, }, // .layout = .right_to_left, .child_gap = 5, }, .children = &[_]UI.Node{ UI.Element(.{ .name = "branch11", .style = .{ .background_colour = .{ .g = 128, .b = 128, .r = 128, }, .size_x = .grow, }, .rect = .{ .h = 40, .w = 40, }, }), UI.Element(.{ .name = "branch12", .style = .{ .background_colour = .{ .g = 128, .r = 128, }, .size_x = .grow, }, .rect = .{ .h = 40, .w = 40, }, }), UI.Element(.{ .name = "branch13", .rect = .{ .h = 40, .w = 40, }, .style = .{ .background_colour = .{ .g = 90, .b = 150, }, }, }), }, }), UI.Element(.{ .name = "branch2", .style = .{ .background_colour = .{ .r = 255, .g = 128, }, .layout = .right_to_left, .child_gap = 4, .padding = .{ .left = 10, .bottom = 10, .right = 10, .top = 10, }, }, .children = &[_]UI.Node{ UI.Element(.{ .name = "branch21", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 255, .b = 150, }, }, }), UI.Element(.{ .name = "branch22", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 90, .b = 150, }, }, }), UI.Element(.{ .name = "branch21", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 255, .b = 150, }, }, }), UI.Element(.{ .name = "branch22", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 90, .b = 150, }, }, }), UI.Element(.{ .name = "branch21", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 255, .b = 150, }, }, }), UI.Element(.{ .name = "branch22", .rect = .{ .h = 30, .w = 30, }, .style = .{ .rounded = 40, .background_colour = .{ .r = 90, .b = 150, }, }, }), }, }), }, }), button(), button(), }; const root = UI.Element(.{ .name = "root", .pos = .{ .x = 0, .y = 0, }, .rect = .{ .h = screenHeight, .w = screenWidth, }, // .on_hover = callback(), // .on_click = callback(), .style = .{ .background_colour = .{ .r = 255, }, .layout = .right_to_left, // .size_x = .fit(), // .size_y = .fixed(), }, .children = child, }); // const arena = [1024]u8{0}; var al = std.heap.ArenaAllocator.init(std.heap.smp_allocator); std.debug.print("root : {f}\n", .{root}); // UI.printTree(sized); // std.debug.print("layout time : {}\n", .{@divTrunc(timer.lap(), std.time.ns_per_ms)}); // Main game loop while (!rl.windowShouldClose()) { // Detect window close button or ESC key // Update //---------------------------------------------------------------------------------- // TODO: Update your variables here //---------------------------------------------------------------------------------- // Draw //---------------------------------------------------------------------------------- rl.beginDrawing(); defer rl.endDrawing(); // std.debug.print("starting layout\n", .{}); _ = timer.lap(); var sized = try UI.resolveSizing(al.allocator(), root); const mouse_pos = rl.getMousePosition(); _ = UI.processInteractions(&sized, .{ .pos = .{ .x = mouse_pos.x, .y = mouse_pos.y, }, .left = rl.isMouseButtonDown(.left), .middle = rl.isMouseButtonDown(.middle), .right = rl.isMouseButtonDown(.right), }); const commands = try UI.getRenderCommands(sized, al.allocator()); // std.debug.print("layout time : {}ms\n", .{ // @as(f32, @floatFromInt(timer.lap())) / @as(f32, @floatFromInt(std.time.ns_per_ms)), // }); for (commands.items) |command| { // std.debug.print("command : {any}\n", .{command}); switch (command) { .rect => |r| { if (r.rounding) |rounding| { rl.drawRectangleRounded( rl.Rectangle.init( r.pos.x, r.pos.y, r.rect.w, r.rect.h, ), rounding / 100.0, 10, rl.Color.init( r.colour.r, r.colour.g, r.colour.b, r.colour.a, ), ); } else { rl.drawRectangleRec(rl.Rectangle.init( r.pos.x, r.pos.y, r.rect.w, r.rect.h, ), rl.Color.init( r.colour.r, r.colour.g, r.colour.b, r.colour.a, )); } }, .text => |t| { const string = @as([:0]const u8, @ptrCast(t.text.string)); rl.drawText(string, @as(i32, @intFromFloat(t.pos.x)), @as(i32, @intFromFloat(t.pos.y)), @as(i32, @intFromFloat(t.text.getTextHeight())), rl.Color.init( t.text.colour.r, t.text.colour.g, t.text.colour.b, t.text.colour.a, )); }, .texture => continue, } } rl.clearBackground(.white); _ = al.reset(.retain_capacity); // rl.drawRectangle(0, 0, 200, 100, .blue); // rl.drawText("Congrats! You created your first window!", 190, 200, 20, .red); //---------------------------------------------------------------------------------- } }