Pack¶
Usage¶
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.
The string values defined here are the string literals that the Pack algorithm accepts. These values are also pre-defined as Python constants in the toga.style.pack module with the same name; however, following Python style, the constants use upper case and dashes are underscores. For example, the Python constant toga.style.pack.SANS_SERIF evaluates as the string literal "sans-serif". (The constant NONE, or "none", is distinct from Python's None.)
Some properties, despite always storing their value in a consistent form, are more liberal in what they accept, and will convert as necessary when assigned alternate forms. Where relevant, these are listed under Accepts.
Toga has a layout debug mode to aid in visually debugging or exploring Pack layouts.
Reference¶
Source code in core/src/toga/style/pack.py
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 | |
display = validated_property(PACK, NONE, initial=PACK)
class-attribute
instance-attribute
¶
Defines how to display the widget.
Allowed values: "pack" or "none"
Default value: "pack"
A value of "pack" will apply the pack layout algorithm to this node and its
descendants. A value of "none" removes the widget from the layout entirely. Space
will be allocated for the widget as if it were there, but the widget itself will
not be visible.
visibility = validated_property(VISIBLE, HIDDEN, initial=VISIBLE)
class-attribute
instance-attribute
¶
Defines whether the widget should be drawn.
Allowed values: "hidden" or "visible"
Default value: "visible"
A value of "visible" means the widget will be displayed. A value of "hidden"
removes the widget from view, but allocates space for the widget as if it were
still in the layout.
Any children of a hidden widget are implicitly removed from view.
If a previously hidden widget is made visible, any children of the widget with a
visibility of "hidden" will remain hidden. Any descendants of the hidden child
will also remain hidden, regardless of their visibility.
direction = validated_property(ROW, COLUMN, initial=ROW)
class-attribute
instance-attribute
¶
The packing direction for children of the box.
Allowed values: "row" or "column"
Default value: "row"
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".
align_items = validated_property(START, CENTER, END)
class-attribute
instance-attribute
¶
The alignment of this box's children along the cross axis.
Allowed values: "start", "center", or "end"
Default value: "start"
Aliases: vertical_align_items in a row, horizontal_align_items in a column
A row's cross axis is vertical, so "start" aligns children to the top, while
"end" aligns them to the bottom. For columns, "start" is on the left if
text_direction is "ltr", and the right if rtl.
justify_content = validated_property(START, CENTER, END, initial=START)
class-attribute
instance-attribute
¶
The alignment of this box's children along the main axis.
Allowed values: "start", "center", or "end"
Default value: "start"
Aliases: horizontal_align_content in a row, vertical_align_content in a
column
A column's main axis is vertical, so "start" aligns children to the top, while
"end" aligns them to the bottom. For rows, "start" is on the left if
text_direction is "ltr", and the right if "rtl".
This property only has an effect if there is some free space in the main axis. For
example, if any children have a non-zero flex value, then they will consume all
the available space, and justify_content will make no difference to the layout.
gap = validated_property(integer=True, initial=0)
class-attribute
instance-attribute
¶
The amount of space to allocate between adjacent children, in CSS pixels.
Allowed values: an integer
Default value: 0
width = validated_property(NONE, integer=True, initial=NONE)
class-attribute
instance-attribute
¶
A specified fixed width for the box, in CSS pixels.
Allowed values: an integer or "none"
Default value: "none"
The final width for the box may be larger, if the children of the box cannot fit inside the specified space.
height = validated_property(NONE, integer=True, initial=NONE)
class-attribute
instance-attribute
¶
A specified fixed height for the box, in CSS pixels.
Allowed values: an integer or "none"
Default value: "none"
The final height for the box may be larger, if the children of the box cannot fit inside the specified space.
flex = validated_property(number=True, initial=0)
class-attribute
instance-attribute
¶
A weighting that is used to compare this box with its siblings when allocating remaining space in a box.
Allowed values: a floating-point number
Default value: 0.0
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.
margin_top = validated_property(integer=True, initial=0)
class-attribute
instance-attribute
¶
margin_right = validated_property(integer=True, initial=0)
class-attribute
instance-attribute
¶
margin_bottom = validated_property(integer=True, initial=0)
class-attribute
instance-attribute
¶
margin_left = validated_property(integer=True, initial=0)
class-attribute
instance-attribute
¶
The amount of space to allocate outside the edge of the box, in CSS pixels.
Allowed values: an integer
Default value: 0
margin = directional_property('margin{}')
class-attribute
instance-attribute
¶
A shorthand for setting the top, right, bottom and left margin with a single declaration.
Allowed values: a tuple consisting of (margin_top, margin_right, margin_bottom,
margin_left)
Default value: (0, 0, 0, 0)
Accepts: an integer or a sequence of 1–4 integers
If 1 integer is provided, that value will be used as the margin for all sides.
If 2 integers are provided, the first value will be used as the margin 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 margin, the second for the left and right margin, and the third for the bottom margin.
If 4 integers are provided, they will be used as the top, right, bottom and left margin, respectively.
color = validated_property(color=True)
class-attribute
instance-attribute
¶
The foreground color for the object being rendered.
Allowed values: a [color][toga.colors.ColorT] or None
Default value: None; will use the system default
Some objects may not use the value.
background_color = validated_property(TRANSPARENT, color=True)
class-attribute
instance-attribute
¶
The background color for the object being rendered.
Allowed values: a [color][toga.colors.ColorT], "transparent", or None
Default value: None; will use the system default
Some objects may not use the value.
text_align = validated_property(LEFT, RIGHT, CENTER, JUSTIFY)
class-attribute
instance-attribute
¶
The alignment of text in the object being rendered.
Allowed values: "left", "right", "center", or "justify"
Default value: "left" if text_direction is "ltr"; "right" if
text_direction is "rtl"
text_direction = validated_property(RTL, LTR, initial=LTR)
class-attribute
instance-attribute
¶
The natural direction of horizontal content.
Allowed values: "rtl" or "ltr"
Default value: "rtl"
font_family = list_property(*SYSTEM_DEFAULT_FONTS, string=True, initial=[SYSTEM])
class-attribute
instance-attribute
¶
A list defining possible font families, in order of preference.
Value: a list of strings
Default value: ["system"]
Accepts: a string or a sequence of strings
The first item that maps to a valid font will be used. If none can be resolved, the system font will be used. Setting to a single string value is the same as setting to a list containing that string as the only item.
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").
Any other value will be checked against the family names previously registered with
Font.register.
On supported platforms (currently Windows and Linux), if Toga doesn't recognize the family as one of its predefined builtins or as a font you've registered, it will attempt to load the requested font from your system before falling back to the default system font.
font_style = validated_property(*FONT_STYLES, initial=NORMAL)
class-attribute
instance-attribute
¶
The style of the font to be used.
Allowed values: "normal", "italic", or "oblique"
Default value: "normal"
Note: Windows and Android do not support the oblique font style. A request for
an "oblique" font will be interpreted as "italic".
font_variant = validated_property(*FONT_VARIANTS, initial=NORMAL)
class-attribute
instance-attribute
¶
The variant of the font to be used.
Allowed values: "normal" or "small_caps"
Default value: "normal"
Note: Windows and Android do not support the small caps variant. A request for a
"small_caps" font will be interpreted as "normal".
font_weight = validated_property(*FONT_WEIGHTS, initial=NORMAL)
class-attribute
instance-attribute
¶
The weight of the font to be used.
Allowed values: "normal" or "bold"
Default value: "normal"
font_size = validated_property(integer=True, initial=SYSTEM_DEFAULT_FONT_SIZE)
class-attribute
instance-attribute
¶
The size of the font to be used, in CSS points.
Allowed values: an integer
Default value: -1; will use the system default size. This is also stored as a
constant named SYSTEM_DEFAULT_FONT_SIZE.
font = composite_property(optional=('font_style', 'font_variant', 'font_weight'), required=('font_size', 'font_family'))
class-attribute
instance-attribute
¶
A shorthand for simultaneously setting multiple properties of a font.
Allowed values: a tuple consisting of (font_style, font_variant, font_weight,
font_size, font_family)
Default value: ("normal", "normal", "normal", -1, ["system"])
Accepts: any valid values (in order) for font_size and font_family, preceded
by any combination and order of valid values for font_style, font_variant, and
font_weight.
Any of the three optional values (style, variant, and weight) not
specified will be reset to "normal".
The relationship between Pack and CSS¶
Pack aims to be a functional subset of CSS. Any Pack layout can be converted into an equivalent CSS layout. After applying this conversion, the CSS layout should be considered a "reference implementation". Any disagreement between the rendering of a converted Pack layout in a browser, and the layout produced by the Toga implementation of Pack should be considered to be either a bug in Toga, or a bug in the mapping.
The mapping that can be used to establish the reference implementation is:
- The reference HTML layout document is rendered in no-quirks mode, with a default CSS stylesheet:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Pack layout testbed</title>
<style>
html, body {
height: 100%;
}
body {
overflow: hidden;
display: flex;
margin: 0;
white-space: pre;
}
div {
display: flex;
white-space: pre;
}
</style>
</head>
<body></body>
</html>
-
The root widget of the Pack layout can be mapped to the
<body>element of the HTML reference document. The rendering area of the browser window becomes the view area that Pack will fill. -
ImageViews map to
<img>elements. The<img>element has an additional style ofobject-fit: containunless bothheightandwidthare defined. -
All other widgets are mapped to
<div>elements. -
The following Pack declarations can be mapped to equivalent CSS declarations:
| Pack property | CSS property |
|---|---|
direction: <str> |
flex-direction: <str> |
display: pack |
display: flex |
flex: <int> |
If direction == "row" and width is set, or direction == "column" and height is set, ignore. Otherwise, flex: <int> 0 auto. |
font_size: <int> |
font-size: <int>pt |
height: <value> |
height: <value>px if value is an integer; height: auto if value is "none". |
margin_top: <int> |
margin-top: <int>px |
margin_bottom: <int> |
margin-bottom: <int>px |
margin_left: <int> |
margin-left: <int>px |
margin_right: <int> |
margin-right: <int>px |
text_direction: <str> |
direction: <str> |
width: <value> |
width: <value>px if value is an integer; width: auto if value is "none". |
- All other Pack declarations should be used as-is as CSS declarations, with underscores being converted to dashes (e.g.,
background_colorbecomesbackground-color).