191 lines
5.2 KiB
Markdown
191 lines
5.2 KiB
Markdown
# 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);
|
|
```
|
|
|
|
## react like componets:
|
|
|
|
you can also create react like componets by creating functions blocks that return a Node, please note that this function is inlined, this is required as children from this node will be shared between all compoents that use this node.
|
|
```zig
|
|
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,
|
|
},
|
|
},
|
|
);
|
|
}
|
|
```
|
|
|
|
## 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
|
|
|