mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
372 lines
12 KiB
Markdown
372 lines
12 KiB
Markdown
# Positioning and Layout of Elements
|
|
|
|
All visual elements are shown in a window. Their position is stored in the `x` and `y`
|
|
properties as coordinates relative to their parent element. The absolute position of an element
|
|
in a window is calculated by adding the parent's position to the element's position. If the
|
|
parent has a grandparent element, then that one is added as well. This calculation continues until
|
|
the top-level element is reached.
|
|
|
|
The size of visual elements is stored in the `width` and `height` properties.
|
|
|
|
You can create an entire graphical user interface by placing the elements in two different
|
|
ways:
|
|
|
|
* Explicitly - by setting the `x`, `y`, `width`, and `height` properties.
|
|
* Automatically - by using layout elements.
|
|
|
|
Explicit placement is great for static scenes with few elements. Layouts are suitable for
|
|
complex user interfaces, because the geometric relationship between the elements is
|
|
expressed in dedicated layout elements. This requires less effort to maintain and helps
|
|
to create scalable user interfaces.
|
|
|
|
## Explicit Placement
|
|
|
|
The following example places two rectangles into a window, a blue one and
|
|
a green one that is a child of the blue:
|
|
|
|
```slint
|
|
// Explicit positioning
|
|
Example := Window {
|
|
width: 200px;
|
|
height: 200px;
|
|
Rectangle {
|
|
x: 100px;
|
|
y: 70px;
|
|
width: parent.width - x;
|
|
height: parent.height - y;
|
|
background: blue;
|
|
Rectangle {
|
|
x: 10px;
|
|
y: 5px;
|
|
width: 50px;
|
|
height: 30px;
|
|
background: green;
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
The position of both rectangles is fixed, as well as the size of the inner green one.
|
|
The outer blue rectangle however has a size that's automatically calculated using binding
|
|
expressions for the `width` and `height` properties. The calculation results in the
|
|
bottom left corner aligning with the corner of the window - it is updated whenever
|
|
the `width` and `height` of the window changes.
|
|
|
|
When specifying explicit values for any of the geometric properties, Slint requires
|
|
you to attach a unit to the number. You can choose between two different units:
|
|
|
|
* Logical pixels, using the `px` unit suffix. This is the recommended unit.
|
|
* Physical pixels, using the `phx` unit suffix
|
|
|
|
Logical pixels scale automatically with the device pixel ratio that your system is
|
|
configured with. For example, on a modern High-DPI display the device pixel ratio can be 2,
|
|
so every logical pixel occupies 2 physical pixels. On an older screen the user
|
|
interface scales without any adaptations.
|
|
|
|
Additionally, the `width` and `height` properties can also be specified as a `%` percentage
|
|
unit, which applies relative to the parent element. For example a `width: 50%` means half
|
|
of the parent's `width`.
|
|
|
|
The default values for `x` and `y` properties are 0, which means they align with their parent
|
|
on the screen.
|
|
|
|
The default values for `width` and `height` depend on the type of element. Some elements are sized
|
|
automatically based on their content, such as `Image`, `Text`, and most widgets. The following elements
|
|
do not have content and therefore default to fill their parent element:
|
|
|
|
* `Rectangle`
|
|
* `TouchArea`
|
|
* `FocusScope`
|
|
* `Flickable`
|
|
* `Clip`
|
|
|
|
## Automatic Placement using Layouts
|
|
|
|
Slint comes with different layout elements that automatically calculate the position and size of their children:
|
|
|
|
* `VerticalLayout` / `HorizontalLayout`: The children are placed along the vertical or horizontal axis.
|
|
* `GridLayout`: The children are placed in a grid of columns and rows.
|
|
* `PathLayout`: The children are placed along a path.
|
|
|
|
Layouts can also be nested, making it possible to create complex user interfaces.
|
|
|
|
You can tune the automatic placement using different constraints, to accommodate the design of your user
|
|
interface. For example each element has a minimum and a maximum size. Set these explicitly using the
|
|
following properties:
|
|
|
|
* `min-width`
|
|
* `min-height`
|
|
* `max-width`
|
|
* `max-height`
|
|
|
|
A layout element also affects the minimum and maximum size of its parent.
|
|
|
|
An element is considered to have a fixed size in a layout when the `width` and `height` is specified directly.
|
|
|
|
When there is extra space in a layout, elements can stretch along the layout axis. You can control this stretch
|
|
factor between the element and its siblings with these properties:
|
|
|
|
* `horizontal-stretch`
|
|
* `vertical-stretch`
|
|
|
|
A value of `0` means that the element will not be stretched at all; unless all siblings also have a stretch
|
|
factor of `0`. Then all the elements will be equally stretched.
|
|
|
|
## Common Properties on Layout Elements
|
|
|
|
All layout elements have the following properties in common:
|
|
|
|
* `spacing`: This controls the spacing between the children.
|
|
* `padding`: This specifies the padding within the layout, the space between the elements and the border of the
|
|
layout.
|
|
|
|
For more fine grained control, the `padding` property can be split into properties for each side of the layout:
|
|
|
|
* `padding-left`
|
|
* `padding-right`
|
|
* `padding-top`
|
|
* `padding-bottom`
|
|
|
|
## `VerticalLayout` and `HorizontalLayout`
|
|
|
|
The `VerticalLayout` and `HorizontalLayout` elements place elements in a column or row.
|
|
By default, they will be stretched or shrunk so that they take the whole space, and their
|
|
alignment can be adjusted.
|
|
|
|
The following example places the blue and yellow rectangle in a row and evenly stretched
|
|
across the 200 logical pixels of `width`:
|
|
|
|
```slint
|
|
// Stretch by default
|
|
Example := Window {
|
|
width: 200px;
|
|
height: 200px;
|
|
HorizontalLayout {
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
}
|
|
```
|
|
|
|
The example below, on the other hand, specifies that the rectangles shell be aligned
|
|
to the start of the layout (the visual left). That results in no stretching but instead
|
|
the rectangles retain their specified minimum width:
|
|
|
|
```slint
|
|
// Unless an alignment is specified
|
|
Example := Window {
|
|
width: 200px;
|
|
height: 200px;
|
|
HorizontalLayout {
|
|
alignment: start;
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
}
|
|
```
|
|
|
|
The example below nests two layouts for a more complex scene:
|
|
|
|
```slint
|
|
Example := Window {
|
|
width: 200px;
|
|
height: 200px;
|
|
HorizontalLayout {
|
|
// Side panel
|
|
Rectangle { background: green; width: 10px; }
|
|
|
|
VerticalLayout {
|
|
padding: 0px;
|
|
//toolbar
|
|
Rectangle { background: blue; height: 7px; }
|
|
|
|
Rectangle {
|
|
border-color: red; border-width: 2px;
|
|
HorizontalLayout {
|
|
Rectangle { border-color: blue; border-width: 2px; }
|
|
Rectangle { border-color: green; border-width: 2px; }
|
|
}
|
|
}
|
|
Rectangle {
|
|
border-color: orange; border-width: 2px;
|
|
HorizontalLayout {
|
|
Rectangle { border-color: black; border-width: 2px; }
|
|
Rectangle { border-color: pink; border-width: 2px; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Alignment
|
|
|
|
Each elements is sized according to their `width` or `height` is specified, otherwise it is
|
|
set to the minimum size which is set with the min-width or min-height property, or
|
|
the minimum size of an inner layout, whatever is bigger.
|
|
Then, the elements are placed according to the alignment.
|
|
The size of elements is bigger than the minimum size only if the alignment is stretch
|
|
|
|
This example show the different alignment possibilities
|
|
|
|
```slint
|
|
Example := Window {
|
|
width: 300px;
|
|
height: 200px;
|
|
VerticalLayout {
|
|
HorizontalLayout {
|
|
alignment: stretch;
|
|
Text { text: "stretch (default)"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: start;
|
|
Text { text: "start"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: end;
|
|
Text { text: "end"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: start;
|
|
Text { text: "start"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: center;
|
|
Text { text: "center"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: space-between;
|
|
Text { text: "space-between"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
HorizontalLayout {
|
|
alignment: space-around;
|
|
Text { text: "space-around"; }
|
|
Rectangle { background: blue; min-width: 20px; }
|
|
Rectangle { background: yellow; min-width: 30px; }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Stretch algorithm
|
|
|
|
When the `alignment` is set to stretch (the default), the elements are sized to their minimum size,
|
|
then the extra space is shared amongst element proportional to their stretch factor set with the
|
|
`horizontal-stretch` and `vertical-stretch` properties. The stretched size will not exceed the maximum size.
|
|
The stretch factor is a floating point number. The elements that have a default content size usually defaults to 0
|
|
while elements that default to the size of their parents defaults to 1.
|
|
An element of a stretch factor of 0 will keep its minimum size, unless all the other elements also have a stretch
|
|
factor of 0 or reached their maximum size.
|
|
|
|
Examples:
|
|
|
|
```slint
|
|
Example := Window {
|
|
width: 300px;
|
|
height: 200px;
|
|
VerticalLayout {
|
|
// Same stretch factor (1 by default): the size is divided equally
|
|
HorizontalLayout {
|
|
Rectangle { background: blue; }
|
|
Rectangle { background: yellow;}
|
|
Rectangle { background: green;}
|
|
}
|
|
// Elements with a bigger min-width are given a bigger size before they expand
|
|
HorizontalLayout {
|
|
Rectangle { background: cyan; min-width: 100px;}
|
|
Rectangle { background: magenta; min-width: 50px;}
|
|
Rectangle { background: gold;}
|
|
}
|
|
// Stretch factor twice as big: grows twice as much
|
|
HorizontalLayout {
|
|
Rectangle { background: navy; horizontal-stretch: 2;}
|
|
Rectangle { background: gray; }
|
|
}
|
|
// All elements not having a maximum width have a stretch factor of 0 so they grow
|
|
HorizontalLayout {
|
|
Rectangle { background: red; max-width: 20px; }
|
|
Rectangle { background: orange; horizontal-stretch: 0; }
|
|
Rectangle { background: pink; horizontal-stretch: 0; }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### `for`
|
|
|
|
The VerticalLayout and Horizontal layout may also contain `for` or `if` expressions, and it does what one expect
|
|
|
|
```slint
|
|
Example := Window {
|
|
width: 200px;
|
|
height: 50px;
|
|
HorizontalLayout {
|
|
Rectangle { background: green; }
|
|
for t in [ "Hello", "World", "!" ] : Text {
|
|
text: t;
|
|
}
|
|
Rectangle { background: blue; }
|
|
}
|
|
}
|
|
```
|
|
|
|
## GridLayout
|
|
|
|
The GridLayout lays the element in a grid.
|
|
Each element gains the properties `row`, `col`, `rowspan`, and `colspan`.
|
|
One can either use a `Row` sub-element, or set the `row` property explicitly.
|
|
These properties must be statically known at compile time, so it is not possible to use arithmetic or depends on properties.
|
|
As of now, the use of `for` or `if` is not allowed in a grid layout.
|
|
|
|
This example use the `Row` element
|
|
|
|
```slint
|
|
Foo := Window {
|
|
width: 200px;
|
|
height: 200px;
|
|
GridLayout {
|
|
spacing: 5px;
|
|
Row {
|
|
Rectangle { background: red; }
|
|
Rectangle { background: blue; }
|
|
}
|
|
Row {
|
|
Rectangle { background: yellow; }
|
|
Rectangle { background: green; }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This example use the `col` and `row` property
|
|
|
|
```slint
|
|
Foo := Window {
|
|
width: 200px;
|
|
height: 150px;
|
|
GridLayout {
|
|
spacing: 0px;
|
|
Rectangle { background: red; }
|
|
Rectangle { background: blue; }
|
|
Rectangle { background: yellow; row: 1; }
|
|
Rectangle { background: green; }
|
|
Rectangle { background: black; col: 2; row: 0; }
|
|
}
|
|
}
|
|
```
|
|
|
|
## `PathLayout`
|
|
|
|
FIXME: write docs
|