Juil - Just UI Layouts
The layout engine targeting to be rich, simple to use, lightweight and framework agnostic.
Build you own GUI for game/applications using powerful solver!
Rendering backend is not supplied and not planned.
You can find examples for HaxeFlixel and Kha in the examples folder
Navigation
Features
-
Just two major classes - a Widget to store values and a Form to solve layout.
-
You can think it as a Figma Auto Layout + constraints.
-
Rich properties:
-
sizeandpositioninfo -
four anchors for each side (
Fixed,Scale,Center) -
layout direction (
Row,Column,Stack) -
stretch policy (
Fixed,Fill,Hug) -
vertical and horizontal
gapwithEvenandFixedpolicy -
content
wrap -
enableflag -
pivot -
marginsandpaddings -
min/maxsizes -
size
aspect -
justifyandalign -
No
Dynamic/Anyor reflection
How to use
- Create widgets directly using
Widgetstructure or throught the factory usingForm.CreateWidget().
var widget = Form.CreateWidget(widget -> {
widget.x = 10;
widget.y = 10;
widget.horizontal = Fixed(100);
widget.vertical = Fixed(100);
});- Create a
Formand pass the root widget.
var form = new Form(widget);- Add to the form widgets and create hierarchy using
Form.addWidget(). Pass the widget you want to add as a first parameter and parent widget as a second.
/// @note Don't forget add root widget to the tree!
// You can use the same widget from the previous step
form.addWidget(widget);
form.addWidget(widget2, widget);
form.addWidget(widget3, widget);
form.addWidget(widget4, widget);
form.addWidget(widget5, widget);- Call the
Form.update()function inside game loop.
For HaxeFlixel:
override public function update(elapsed:Float) {
super.update(elapsed);
// Update the form
form.update();
}-
Receive input and react:
-
Set input argument to true
Form.CreateWidget(widget -> {
widget.x = 10;
widget.y = 10;
...
}, true); // <-- this one- Use either form attribute
onInput
form.onInput = widget -> {
if (widget.area.isReleased && !widget.area.isDropped) {
trace("clicked!");
}
};- ... or the
areaattribute directly from widget
if (widget.area.isDragging) {
widget.x += widget.area.mouseDelta.x;
widget.y += widget.area.mouseDelta.y;
}- Update your renderer
For HaxeFlixel:
sprite.setPosition(widget.x + widget.w / 2.0, widget.y + widget.h / 2.0);- After you created a form, you can inject subtree
// Create widgets
var subtreeRoot = Form.CreateWidget(widget -> {
widget.horizontal = Fill;
widget.vertical = Fill;
widget.direction = Row;
widget.padding = All(5);
});
var subtreeChild1 = Form.CreateWidget(widget -> {
widget.horizontal = Fill;
widget.vertical = Fill;
});
var subtreeChild2 = Form.CreateWidget(widget -> {
widget.horizontal = Fill;
widget.vertical = Fill;
});
// Create subtree
// parent => array of children
var subtree = new Map<Widget, Array<Widget>>();
subtree.set(subtreeRoot, [subtreeChild1, subtreeChild2]);
subtree.set(subtreeChild1, []); /// @note Don't forget to set leafs as empty arrays!!
subtree.set(subtreeChild2, []);
// Inject subtree
/// @note You will override existed widgets if they were presented in the tree already
form.addSubtree(parent, subtreeRoot, subtree);
// You can remove subtree also
/// @note In most cases the first and the second arguments are the same you used to add subtree
/// But it's not necessary to remove the whole original subtree -
/// you can remove subtree of the subtree
form.removeSubtree(parent, subtreeRoot);- If you want to validate your form, you can use validation methods
// Validation will print the error, possible solution and return status
// Use to check if root is null
var form = new Form(null);
if (!form.validateRoot())
return;
// Use to check if tree contains entry point
form.validateEntry();
// Use to check null's in tree
form.validateHierarchy();
// Use to check is widget with 0 width or height exists
form.validateSizes();
// You can find examples in the FormTest.testValidation()
Also, you can validate everything for simplicity
form.validateAll();
Community
You can message me via email
join my Discord server
or DM in Discord @teslotik