juil

Lightweight, simple to use GUI solving engine for your game/application
https://github.com/Teslotik/Juil

To install, run:

haxelib install juil 0.0.1 

See using Haxelib in Haxelib documentation for more information.

README.md

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

  1. Just two major classes - a Widget to store values and a Form to solve layout.

  2. You can think it as a Figma Auto Layout + constraints.

  3. Rich properties:

  4. size and position info

  5. four anchors for each side (Fixed, Scale, Center)

  6. layout direction (Row, Column, Stack)

  7. stretch policy (Fixed, Fill, Hug)

  8. vertical and horizontal gap with Even and Fixed policy

  9. content wrap

  10. enable flag

  11. pivot

  12. margins and paddings

  13. min/max sizes

  14. size aspect

  15. justify and align

  16. No Dynamic/Any or reflection

How to use

  1. Create widgets directly using Widget structure or throught the factory using Form.CreateWidget().
var widget = Form.CreateWidget(widget -> {
    widget.x = 10;
    widget.y = 10;
    widget.horizontal = Fixed(100);
    widget.vertical = Fixed(100);
});
  1. Create a Form and pass the root widget.
var form = new Form(widget);
  1. 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);
  1. Call the Form.update() function inside game loop.

For HaxeFlixel:

override public function update(elapsed:Float) {
    super.update(elapsed);
    
    // Update the form
    form.update();
}
  1. Receive input and react:

  2. 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 area attribute directly from widget
if (widget.area.isDragging) {
    widget.x += widget.area.mouseDelta.x;
    widget.y += widget.area.mouseDelta.y;
}
  1. Update your renderer

For HaxeFlixel:

sprite.setPosition(widget.x + widget.w / 2.0, widget.y + widget.h / 2.0);
  1. 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);
  1. 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

Screenshots

PBR Convertor

Painting app

Painting app redesigned

Contributors
Teslotik
Version
0.0.1
Published
5 days ago
Dependencies
License
MIT

All libraries are free

Every month, more than a thousand developers use Haxelib to find, share, and reuse code — and assemble it in powerful new ways. Enjoy Haxe; It is great!

Explore Haxe

Haxe Manual

Haxe Code Cookbook

Haxe API documentation

You can try Haxe in the browser! try.haxe.org

Join us on GitHub!

Haxe is being developed on GitHub. Feel free to contribute or report issues to our projects.

Haxe on GitHub