#------------------------------------------------------------------------------
# Copyright (c) 2012, Enthought, Inc.
# All rights reserved.
#------------------------------------------------------------------------------
from traits.api import Instance, Str
from enaml.layout.constraint_variable import ConstraintVariable
from enaml.layout.layout_helpers import align, hbox, vbox
from .container import Container
[docs]class Form(Container):
""" A Container subclass that arranges its children in two columns.
The left column is typically Labels (but this is not a requirement).
The right are the actual widgets for data entry. The children should
be in alternating label/widget order. If there are an odd number
of children, the last child will span both columns.
The Form provides an extra constraint variable, 'midline', which
is used as the alignment anchor for the columns.
"""
#: The ConstraintVariable giving the midline along which the labels
#: and widgets are aligned.
midline = Instance(ConstraintVariable)
def _midline_default(self):
return ConstraintVariable('midline', self.object_id)
#: The strength for the form layout constraints.
# FIXME: Use an Enum.
layout_strength = Str('strong')
#: A form hugs its height strongly by default. Forms are typcially
#: used to display vertical arrangements of widgets, with forms
#: often being stacked on top of each other. For this case, hugging
#: the height is desired.
hug_height = 'strong'
def _component_constraints(self):
""" Supplies the constraints which layout the children in a
two column form.
"""
# FIXME: do something sensible when children are not visible.
children = list(self.widgets)
labels = children[::2]
widgets = children[1::2]
n_labels = len(labels)
n_widgets = len(widgets)
if n_labels != n_widgets:
if n_labels > n_widgets:
odd_child = labels.pop()
else:
odd_child = widgets.pop()
else:
odd_child = None
layout_strength = self.layout_strength
constraints = []
# Align the left side of each widget with the midline constraint
# variable of the form.
midline = self.midline
for widget in widgets:
cn = (widget.left == midline) | layout_strength
constraints.append(cn)
# Arrange each label/widget pair horizontally in the form
# XXX this is a highly inefficient way to generate these
# constraints. It starts to be noticeably slow when the
# form has around 20 rows. This can be done better.
labels_widgets = zip(labels, widgets)
vbox_args = [hbox(label, widget) for label, widget in labels_widgets]
if odd_child is not None:
vbox_args.append(odd_child)
constraints.append(vbox(*vbox_args))
for label, widget in labels_widgets:
# FIXME: baselines would be much better.
constraints.append(align('v_center', label, widget) | layout_strength)
return constraints
def _default_constraints(self):
""" Overridden parent class method which returns an empty list.
This disables the vbox constraints supplied by the superclass
Container. All Form constraints are generated by the
'_component_constraints' method.
"""
return []