Layout
Layout is probably the most difficult topic in any UI system. It's not only how the API gets used but its often a mindset about how to approach the problem at hand. Sometimes you get lucky and the design you are implementing is simple enough that built in layout components can mostly get you there, but in almost every design I've ever personally worked with, I needed to get my hands dirty and get creative with how the layout was implemented.
The goal of this document is to orient you with 'how-to-think-about-layout' in Evolve.
The basics
We'll start relatively simple. We have two cases: template
and typography
. Both cases follow the same default rule:
they size themselves according to their content. If there is no content, the size is 0 by default.
So what is 'content'? This can be text content in the case of typogrophy
, padding, and/or other child elements.
The box model
Evolve uses the standard CSS border-box model.
+-----------------------------+
| Margin |
| +---------------------+ |
| | Border | |
| | +---------------+ | |
| | | Padding | | |
| | | +---------+ | | |
| | | | Content | | | |
| | | +---------+ | | |
| | +---------------+ | |
| +---------------------+ |
+-----------------------------+
- Margin -- Space between sibling elements in
- Padding -- Space between the edge of element's border and it's content
- Border -- Space between the theoretical edge of the element and it's padding
- Content -- All the things inside the element, ie text, images, other elements
Sizes
Evolve uses a handful of measurement types to measure elements, paddings, offsets, alignments, etc. The most important ones are UIMeasurement for sizing elements and UISpaceSize for paddings and margins.
Then to actually set an element's size, we use the style properties
- PreferredWidth
- PreferredHeight
- MinWidth
- MinHeight
- MaxWidth
- MaxHeight
We also have the shorthands which set both width and height axes at the same time
- PreferredSize
- MinSize
- MaxSize
We use Preferred
width/height because the layout system has some ways of increasing/reducing the size of elements
based on the algorithm used, ie if the PreferredWidth
is 300px
but the MaxWidth
is 200px
, the element will clamp
to it's max size, disregarding the PreferredWidth
value.
See the docs on style properties for more details.
Templates
Templates will default to their content size on both the width and the height axis, and will arrange their children vertically. A side effect of defaulting to content size is that by default, with no content, an element's size is 0 on both width and height.
template Element; // no content, no style means these have no size unless they have content.
template Basics {
// 3 elements with no size means the parent has no size.
render {
Element();
Element();
Element();
}
}
If we were to render this template, we'd see nothing. Let's give those some sizes:
style big {
PreferredSize = 300px;
BackgroundColor = red;
}
style small {
PreferredSize = 100px;
BackgroundColor = blue;
}
template Element; // no content, no style means these have no size unless they have content.
template Basics {
// 3 elements with no size means the parent has no size.
render {
Element(style = [@small]);
Element(style = [@big]);
Element(style = [@small]);
}
}
This would render the boxes vertically with their respective sizes, so the total width of Basics
would be 300px,
and the total height would be 500px
We could change this to a horizontal layout like this:
// the <> syntax matches based on an element name
style <Basics> {
LayoutType = Horizontal;
}
style big {
PreferredSize = 300px;
}
style small {
PreferredSize = 100px;
}
template Element;
template Basics {
render {
Element(style = [@small]);
Element(style = [@big]);
Element(style = [@small]);
}
}
This would render the boxes vertically with their respective sizes, so the total width of Basics
would be 500px,
and the total height would be 300px
Typography
Typography actually follows the exact same rules, except that usually when we think about typography elements, we assume
they contain some text. So text is content, which means that a typography
element will default to be as big as its text.
This also means that because the text layout is greedy, unless a text is given a width or some explicit new lines, it will not wrap by default.
In order for text to wrap, it needs to be given a non-content sized width, or it needs to contain new lines and have
it's LineBreakMode
set to NewLinesOnly
.