cuicui_layout
cuicui_layout is a very primitive layouting algorithm implemented in bevy for bevy.
It is similar to CSS, but without the headache. The philosophy is:
You can always predict how it will look like
cuicui_layout is fully independent from other cuicui crates, you can disable
all default feature and have a bare-bone plugin that only adds layouting components
and systems to your bevy game.
However, cuicui_layout also integrates with cuicui_dsl and cuicui_chirp.
See their respective documentation pages for why you’d want to use them as well.
When to use cuicui_layout?
cuicui_layout is always a better choice over Flexbox, the default bevy UI
layouting algorithm. I’m however not claiming that it is better than other
similar non-flexbox layouting algorithm.
Here is some reasons you’d prefer cuicui_layout over other layouting
algorithms:
- Friendly algo with less things to keep in your head and good defaults.
- Uses and takes full advantage of the bevy ECS.
- Only controls
LayoutRect, notTransform, you need to add a system that setsTransformbased onLayoutRect. - Fully flexible and extensible, can be used with
bevy_ui,bevy_sprite, your own stuff. - Helpful and fully detailed error messages when things are incoherent or broken. As opposed to FlexBox, which goes “this is fine 🔥🐶🔥” and leaves you to guess why things do not turn out as expected.
- This is a single-pass algo, so more efficient than flexbox.
- An extensive debugging overlay.
How to use cuicui_layout?
Cargo features
debug: Enable the debug overlayreflect(default): Enablebevy_reflectimpls for layout components.chirp(default): Enable chirpParseDslimplementation forLayoutDsldsl(default): Define and exportLayoutDslDslBundleimpl for thedsl!macro
Layouting
cuicui_layout exposes the following Components to control layouting:
Node: A layout node, either a container holding other nodes as bevyChildrenor a leaf node.Root: The root of a node hierarchy. You may have several, all computations start from the root.ScreenRoot: If you add this component to aRootentity, it will keep the same size as the camera with theLayoutRootCameracomponent.
See the Rule and Container documentation for detailed explanation.
In short: a Node has independent Rules on the x and y axis. When the
node is a Container, it also has additional properties that manages how
children are distributed within the container.
Those additional properties are:
Flow: The direction in which the children are distributedAlignment: Where on the cross axis are nodes aligned.Distribution: How to distribute the children of this container.margin: How much margin to put on main and cross axis
By default, items are aligned at the center of the container, distributed on the flow direction evenly within the container.
A Rule tells the size of the Node, it can depend on the size of its children,
the size of its parent or be a fixed value.
There isn’t more to it, that’s pretty much all of cuicui_layout.
If this wasn’t clear enough please read the Rule and Container documentation.
Content-sized
It is possible to size leaf nodes based on components present on the same entity.
Use the content_sized traits to do that.
Debugging
cuicui_layout has an integrated debugger. Enable it with the cuicui_layout/debug
cargo feature.
The debugger is an overlay displaying the extent of Nodes and the direction
of their rules.
Why not Flexbox
You are writing text to get 2d visual results on screen.
The translation from text to screen should be trivial, easy to do in your head.
Otherwise you need visual feedback to get what you want.
Bevy, even with hot reloading or bevy-inspector-egui
will always have extremely slow visual feedback.
Flexbox has too many parameters and depends on implicit properties of UI elements, it is not possible to emulate it in your head.
cuicui’s layout, in contrast to Flexbox is easy to fit in your head. In fact, I will forecefully push cuicui’s layout algorithm in your head in two short bullet points.
- A node can be a
Node::Containerand distribute its children along aDirectioneither by evenly spacing them (Distribution::FillMain) or putting them directly one after another (Distribution::Start). - A
Container’s size can be expressed as a static value, a fraction of the size of what contains it, or a multiple of what it contains. - The content of a
Containercan beAlignmentto the start, end or center of its parent (by default it’s centered).
That’s it. There are some edge cases, but cuicui will yell at you
tell you nicely when you hit them and tell you how to handle them properly.
Flexbox FAQ
Q: Where is padding?
A: padding is equivalent to margin in cuicui_layout. margin and border
doesn’t make conceptual sense.
Q: Why not call it padding then?
A: Look at the dictionary definition of “margin” and “padding”.
Q: How do I center a node?
A: nodes are centered by default, make sure the parent’s container size
has the expected size.
Q: What is the equivalent of flex_direction?
A: use row and column
Q: What are the equivalents of column-reverse and row-reverse?
A: None. Use Alignment::End and swap your elements! Note that the *-reverse
flows in flexbox are very useful for internationalization. However,
when making a game, it is not enough to just swap the elements! Artistic control is
paramount and internationalization needs to be taken as a whole in the context of the UI.
Q: What is the equivalent of flex_wrap?
A: None, do you really need it?
Q: What is the equivalent of align_item, align_self, align_content, justify_content?
A: After 5 years of working with CSS, I still have no clue which one does what,
and whether they really do anything, so I won’t adventure an asnwer.
Q: What is the equivalent of flex_grow, flex_shrink, flex_basis, gap?
A: Do you even know what they do?
Q: Why can’t child container overflow their parents?
A: It’s likely you didn’t expect this, so we report it as an error.
Q: How do I make a grid?
A: cuicui_layout is currently not capable of managing a grid of nodes.
This might be added in the future.