Enable Constraints Layout¶
This document describes the constraints-based layout system that is being proposed as the new layout model going forward. Familiarity with Enaml and its layout system is helpful but not required.
Using Constraints¶
ConstraintsContainer
is a Container
subclass which uses the
Cassowary constraint solver to determine the layout of its child
Component
instances. This is achieved by adding constraint variables
to the Component
class which define a simple box model:
layout_height
: The height of the component.layout_width
: The width of the component.left
: The left edge of the component.right
: The right edge of the component.top
: The top edge of the component.bottom
: The bottom edge of the component.h_center
: The vertical center line between the left and right edgesv_center
: The horizontal center line between the top and bottom edges
Additionally, there are some constraints which only exist on
ConstraintsContainer
:
contents_height
: The height of the container.contents_width
: The width of the container.contents_left
: The left edge of the container.contents_right
: The right edge of the container.contents_top
: The top edge of the container.contents_bottom
: The bottom edge of the container.contents_h_center
: The vertical center line of the container.contents_v_center
: The horizontal center line of the container.
These variables can be used in linear inequality expressions which make up the layout constraints of a container:
def build_hierarchy():
container = ConstraintsContainer()
one = Component()
two = Component()
container.add(one, two)
container.layout_constraints = [
one.layout_width == two.layout_width * 2.0,
one.layout_height == two.layout_height,
# ... and so on ...
]
return container
For more complicated layouts, the layout_constraints
trait on a
ConstraintsContainer
can be a callable
. The function is
passed a reference to the container and should return a list of
LinearContraints
objects or layout helper instances (as described below).
def create_container(self):
self.container = ConstraintsContainer()
self.container.add(self.bar)
self.container.layout_constraints = self.my_layout_constraints
def my_layout_constraints(self, container):
cns = []
if self.foo:
cns.append(self.foo.layout_height <= 300)
cns.append(hbox(self.foo, self.bar))
cns.append(self.bar.layout_width == 250)
return cns
If layout_constraints
is callable, it will be invoked each time a
component is added to the container or whenever the layout_size_hint
trait changes on a child component.
Layout Helpers¶
In practice, it’s too tedious to specify all the constraints for a rich UI layout. To aid in the generation of layouts, the layout helpers from Enaml are also available in Enable. The layout helpers are:
spacer
: Creates space between two adjacent components.
-
horizontal
(*components[, spacing=10])¶ Takes a list of components and lines them up using their left and right edges.
Parameters: - components – A sequence of
Component
orspacer
objects. - spacing (integer >= 0) – How many pixels of inter-element spacing to use
- components – A sequence of
-
vertical
(*components[, spacing=10])¶ Takes a list of components and lines them up using their top and bottom edges.
Parameters: - components – A sequence of
Component
orspacer
objects. - spacing (integer >= 0) – How many pixels of inter-element spacing to use
- components – A sequence of
-
hbox
(*components[, spacing=10, margins=...])¶ Like
horizontal()
, but ensures the height of components matches the container.Parameters: - components – A sequence of
Component
orspacer
objects. - spacing (integer >= 0) – How many pixels of inter-element spacing to use
- margins – An int, tuple of ints, or
Box
of ints >= 0 which indicate how many pixels of margin to add around the bounds of the box. The default is 0.
- components – A sequence of
-
vbox
(*components[, spacing=10, margins=...])¶ Like
vertical()
, but ensures the width of components matches the container.Parameters: - components – A sequence of
Component
orspacer
objects. - spacing (integer >= 0) – How many pixels of inter-element spacing to use
- margins – An int, tuple of ints, or
Box
of ints >= 0 which indicate how many pixels of margin to add around the bounds of the box. The default is 0.
- components – A sequence of
-
align
(anchor, *components[, spacing=10])¶ Aligns a single constraint across multiple components.
Parameters: - anchor – The name of a constraint variable that exists on all of the components.
- components – A sequence of
Component
objects. Spacers are not allowed. - spacing (integer >= 0) – How many pixels of inter-element spacing to use
-
grid
(*rows[, row_align='', row_spacing=10, column_align='', column_spacing=10, margins=...])¶ Creates an NxM grid of components. Components may span multiple columns or rows.
Parameters: - rows – A sequence of sequences of
Component
objects - row_align (string) – The name of a constraint variable on an item. If given, it is used to add constraints on the alignment of items in a row. The constraints will only be applied to items that do not span rows.
- row_spacing (integer >= 0) – Indicates how many pixels of space should be placed between rows in the grid. The default is 10.
- column_align (string) – The name of a constraint variable on an item. If given, it is used to add constraints on the alignment of items in a column. The constraints will only be applied to items that do not span columns.
- column_spacing (integer >= 0) – Indicates how many pixels of space should be placed between columns in the grid. The default is 10.
- margins – An int, tuple of ints, or
Box
of ints >= 0 which indicate how many pixels of margin to add around the bounds of the box. The default is 0.
- rows – A sequence of sequences of
Fine Tuning Layouts¶
Component
defines a Tuple
trait layout_size_hint
which
controls the minimum size of a component when it’s part of a contraints layout.
Additionally, Component
defines some strength traits that can be used
to fine tune the behavior of a component instance during layout. They are:
hug_height
: How strongly a component prefers the height of its size hint when it could grow.hug_width
: How strongly a component prefers the width of its size hint when it could grow.resist_height
: How strongly a component resists its height being made smaller than its size hint.resist_width
: How strongly a component resists its width being made smaller than its size hint.
The allow values for these strengths are: ‘required’, ‘strong’, ‘medium’, and ‘weak’.