The Pack Style Engine#
Toga’s default style engine, Pack, is a layout algorithm based around the idea of packing boxes inside boxes. Each box specifies a direction for its children, and each child specifies how it will consume the available space - either as a specific width, or as a proportion of the available width. Other properties exist to control color, text alignment and so on.
It is similar in some ways to the CSS Flexbox algorithm; but dramatically simplified, as there is no allowance for overflowing boxes.
Pack style properties#
display
#
Values: pack
| none
Initial value: pack
Used to define the how to display the element. A value of pack
will apply
the pack layout algorithm to this node and its descendents. A value of
none
removes the element from the layout entirely. Space will be allocated
for the element as if it were there, but the element itself will not be
visible.
visibility
#
Values: visible
| none
Initial value: visible
Used to define whether the element should be drawn. A value of visible
means the element will be displayed. A value of none
removes the element,
but still allocates space for the element as if it were in the element tree.
direction
#
Values: row
| column
Initial value: row
The packing direction for children of the box. A value of column
indicates
children will be stacked vertically, from top to bottom. A value of row
indicates children will be packed horizontally; left-to-right if
text_direction
is ltr
, or right-to-left if text_direction
is rtl
.
alignment
#
Values: top
| bottom
| left
| right
| center
Initial value: top
if direction is row
; left
if direction is column
The alignment of children relative to the outside of the packed box.
If the box is a column
box, only the values left
, right
and
center
are honored.
If the box is a row
box, only the values top
, bottom
and center
are honored.
If a value is provided, but the value isn’t honored, the alignment reverts to the default for the direction.
width
#
Values: <integer>
| none
Initial value: none
Specify a fixed width for the box.
The final width for the box may be larger, if the children of the box cannot fit inside the specified space.
height
#
Values: <integer>
| none
Initial value: none
Specify a fixed height for the box.
The final height for the box may be larger, if the children of the box cannot fit inside the specified space.
flex
#
Values: <number>
Initial value: 0
A weighting that is used to compare this box with its siblings when allocating remaining space in a box.
Once fixed space allocations have been performed, this box will assume flex
/ (sum of all flex for all siblings)
of all remaining available space in the
direction of the parent’s layout.
padding_top
#
padding_right
#
padding_bottom
#
padding_left
#
Values: <integer>
Initial value: 0
The amount of space to allocate between the edge of the box, and the edge of content in the box, on the top, right, bottom and left sides, respectively.
padding
#
Values: <integer>
or <tuple>
of length 1-4
A shorthand for setting the top, right, bottom and left padding with a single declaration.
If 1 integer is provided, that value will be used as the padding for all sides.
If 2 integers are provided, the first value will be used as the padding for the top and bottom; the second will be used as the value for the left and right.
If 3 integers are provided, the first value will be used as the top padding, the second for the left and right padding, and the third for the bottom padding.
If 4 integers are provided, they will be used as the top, right, bottom and left padding, respectively.
color
#
Values: <color>
Initial value: System default
Set the foreground color for the object being rendered.
Some objects may not use the value.
background_color
#
Values: <color>
| transparent
Initial value: The platform default background color
Set the background color for the object being rendered.
Some objects may not use the value.
text_align
#
Values: left
| right
| center
| justify
Initial value: left
if text_direction
is ltr
; right
if text_direction
is rtl
Defines the alignment of text in the object being rendered.
text_direction
#
Values: rtl
| ltr
Initial value: rtl
Defines the natural direction of horizontal content.
font_family
#
Values: system
| serif``| ``sans-serif
| cursive
| fantasy
| monospace
| <string>
Initial value: system
The font family to be used.
A value of system
indicates that whatever is a system-appropriate font
should be used.
A value of serif
, sans-serif
, cursive
, fantasy
, or monospace
will use a system defined font that matches the description (e.g.,”Times New Roman” for serif
, “Courier New” for monospace
).
Otherwise, any font name can be specified. If the font name cannot be resolved, the system font will be used.
font_variant
#
Values: normal
| small_caps
Initial value: normal
The variant of the font to be used.
font_weight
#
Values: normal
| bold
Initial value: normal
The weight of the font to be used.
font_size
#
Values: <integer>
Initial value: System default
font
#
A shorthand value
The Pack algorithm#
The pack algorithm is applied to the root of a layout tree, with a box specifying the allocated width and allocated height.
Establish the available width
If the element has a
width
specified, the available width is set to that width.Otherwise, the adjusted view width is set to the view width, less the amount of
padding_left
andpadding_right
. If this results in a value less than 0, the adjusted view width is set to 0.If the element has a fixed intrinsic width, the available width is set to the intrinsic width.
If the element has a minimum intrinsic width, the available width is fixed to the maximum of the adjusted view width and the intrinsic minimum width.
If the element does not have an intrinsic width, the available width is set to the adjusted view width.
Establish the available height
If the element has a
height
specified, the available height is set to that height.Otherwise, the adjusted view height is set to the view height, less the amount of
padding_top
andpadding_bottom
. If this results in a value less than 0, the adjusted view height is set to 0.If the element has a fixed intrinsic height, the available height is set to the intrinsic height.
If the element has a minimum intrinsic height, the available height is fixed to the maximum of the adjusted view height and the intrinsic minimum height.
If the element does not have an intrinsic height, the available height is set to the adjusted view height.
Layout children
If the element has no children, the final width of the element is set to the available width, and the final height of the element is set to the available height.
Otherwise, the element is a parent element, the final width is set to 0, and the children are laid out.
If the parent element has a
display
value ofrow
, it is a row box, and child layout occurs as follows:Allocated fixed width elements
This step is performed on every child, in definition order.
If the child has:
an explicitly specified
width
; ora fixed intrinsic width; or
a
flex
value of 0
then the child is then laid out using a recursive call to this algorithm, using the current available width and available height.
The child’s full width is then evaluated as the content width allocated by the recursive layout call, plus the
padding_left
andpadding_right
of the child. The final width of the parent element is increased by the child’s full width; the available width of the parent element is decreased by the child’s full width.Evaluate flex quantum value
The flex total is set to the sum of the
flex
value for every element that wasnt’ laid out in substep 1.If the available width is less than 0, or the flex total is 0, the flex quantum is set to 0. Otherwise, the flex quantum is set to the available width divided by the flex total.
Evaluate the flexible width elements
This step is performed on every child, in definition order.
If the child was laid out in step 1, no layout is required, and this step can be skipped.
Otherwise, the child’s flex allocation is the product of the flex quantum and the child’s
flex
value.If the child has a minimum intrinsic width, the child’s allocated width is set to the maximum of the flex allocation and the minimum intrinsic width.
Otherwise, the child’s allocated width is set to the flex allocation.
The child is then laid out using a recursive call to this algorithm, using the child’s allocated width and the available height.
The child’s full width is then evaluated as the content width allocated by the recursive layout call, plus the
padding_left
andpadding_right
of the child. The overall width of the parent element is increased by the child’s full width.Evaluate row height, and set the horizontal position of each element.
The current horizontal offset is set to 0, and then this step is performed on every child, in definition order.
If the
text_direction
of parent element isltr
, the left position of the child element is set to the current horizontal offset plus the child’spadding_left
. The current horizontal offset is then increased by the child’s content width plus the child’spadding_right
.If the
text_direction
of the parent element isrtl
, the right position of the child element is set to the parent’s final width, less the offset, less the child’spadding_right
. The current horizontal offset is then increased by the child’s content width plus the child’spadding_left
.Set the vertical position of each child inside the row
This step is performed on every child, in definition order.
The extra height for a child is defined as the difference between the parent elements final height and the child’s full height.
If the parent element has an
alignment
value oftop
, the vertical position of the child is set to 0, relative to the parent.If the parent element has an
alignment
value ofbottom
, the vertical position of the child is set to the extra height, relative to the parent.If the parent element has an
alignment
value ofcenter
, the vertical position of the child is set to 1/2 of the extra height, relative to the parent.
If the parent element has a
display
value ofcolumn
, it is a column box, and child layout occurs as follows:Allocated fixed height elements
This step is performed on every child, in definition order.
If the child has:
an explicitly specified
height
; ora fixed intrinsic height; or
a
flex
value of 0
then the child is then laid out using a recursive call to this algorithm, using the current available width and available height.
The child’s full height is then evaluated as the content height allocated by the recursive layout call, plus the
padding_top
andpadding_bottom
of the child. The final height of the parent element is increased by the child’s full height; the available height of the parent element is decreased by the child’s full height.Evaluate flex quantum value
The flex total is set to the sum of the
flex
value for every element that wasn’t laid out in substep 1.If the available height is less than 0, or the flex total is 0, the flex quantum is set to 0. Otherwise, the flex quantum is set to the available height divided by the flex total.
Evaluate the flexible height elements
This step is performed on every child, in definition order.
If the child was laid out in step 1, no layout is required, and this step can be skipped.
Otherwise, the child’s flex allocation is the product of the flex quantum and the child’s
flex
value.If the child has a minimum intrinsic height, the child’s allocated height is set to the maximum of the flex allocation and the minimum intrinsic height.
Otherwise, the child’s allocated height is set to the flex allocation.
The child is then laid out using a recursive call to this algorithm, using the child’s allocated height and the available width.
The child’s full height is then evaluated as the content height allocated by the recursive layout call, plus the
padding_top
andpadding_bottom
of the child. The overall height of the parent element is increased by the child’s full height.Evaluate column width, and set the vertical position of each element.
The current vertical offset is set to 0, and then this step is performed on every child, in definition order.
The top position of the child element is set to the current vertical offset plus the child’s
padding_top
. The current vertical offset is then increased by the child’s content height plus the child’spadding_bottom
.Set the horizontal position of each child inside the column
This step is performed on every child, in definition order.
The extra width for a child is defined as the difference between the parent element’s final width and the child’s full width.
If the parent element has an
alignment
value ofleft
, the horizontal position of the child is set to 0, relative to the parent.If the parent element has an
alignment
value ofright
, the horizontal position of the child is set to the extra width, relative to the parent.If the parent element has an
alignment
value ofcenter
, the horizontal position of the child is set to 1/2 of the extra width, relative to the parent.