# Another render agnostic immedate mode ui layout libary Shoots is another render agnostic immedate mode ui layout libary but this time written in zig. you can check out examples for how the libary works, but here are the basic principles: everything is a node: ```zig const root = UI.Element(.{ .name = "button", .rect = .{ .h = 20, .w = 60, }, .on_click = .{ .func = &updateButton, .data = &.{}, }, .on_hover = .{ .func = &hoverButton, .data = &.{}, }, .style = .{ .background_colour = .{ .g = 255, }, .rounded = 25, }, }, .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, }), ), }, }); ``` there are 3 differnt types of nodes - elements these are basically your html divs - text text is currently just one line - textures all the fun images you want to include once you have your node tree setup you should create an arena allocator, since on each render a clone of the node tree will be created this is to ensure that its a forgetful ui system. ```zig var al = std.heap.ArenaAllocator.init(std.heap.smp_allocator); ``` now using the arena you can either use: ```zig var sized = try UI.resolveSizing(al.allocator(), root); OR // clone the root node var new_tree: Node = try UI.deepClone(root, alloc); // this is needed as a place holder for the root node var base_node: Node = Node{ .element = Ele{ .children = &[_]Node{ root, }, } }; // go through and computes the sizes of all the child elements computeSizes(&new_tree, &base_node); // grows the child elements computeGrowElements(&new_tree); // computes the pos computePositions(&new_tree); ``` This will clone the tree, compute the sizes of the rectangles compute, grow all the child elements, and lastly compute all the positions of the nodes. next check for any interactions that may occur, these are things like on hover and on click: ```zig const needs_redrawn = UI.processInteractions(&sized, .{ .pos = .{ .x = mouse_pos.x, .y = mouse_pos.y, }, .left = rl.isMouseButtonDown(.left), .middle = rl.isMouseButtonDown(.middle), .right = rl.isMouseButtonDown(.right), }); ``` this function returns a bool to determin if the current tree needs to be redrawn, this should be useful in some case. and finally you can generate the render commands, these commands tell your render where to draw the rectangles on the screen. ```zig const commands = try UI.getRenderCommands(sized, al.allocator()); ``` you can checkout [the raylib example for how to parse these render commands](./examples/raylib-example/src/main.zig) and finally free the arena with a retained_capacity as the ui will more then likely be the exact same size and should only require some few addtional allocs. ``` _ = al.reset(.retain_capacity); ``` ## adding shoots to your project fetch the repo ``` > zig fetch --save git+https://git.sirlilpanda.studio/sirlilpanda/shoots ``` add to build.zig ```zig const shoots = b.dependency("shoots", .{ .target = target, .optimize = optimize, }); exe.root_module.addImport("shoots", shoots.module("shoots")); ``` ## resources if you want to either learn out Immediate-Mode ui or make your own: - [How Clay's UI Layout Algorithm Works](https://www.youtube.com/watch?v=by9lQvpvMIc) really good for the layout algrothim - [Immediate-Mode Graphical User Interfaces - 2005](https://www.youtube.com/watch?v=Z1qyvQsjK5Y) good video on explaining the concepts behind immediate mode guis - [how-to-write-a-flexbox-layout-engine](https://tchayen.com/how-to-write-a-flexbox-layout-engine) perfect for getting an overview of how all the componets togeather - [microui](https://github.com/rxi/microui) some further inporation for how to create ui frameworks