1. Using the Library¶
Layout is designed for the flexible composition of document layouts, particularly complex charts, and multi-page documents of algorithmically calculated data. It isn’t designed to be used as a framework to flow in large amounts of body text, as the sizing algorithms used don’t take account of text flows.
1.1. Overview¶
There are three stages in using the library:
1. Define classes that will render the content you need to
render. There are a selection of classes in the layout.elements
package that cover some basic needs, but often custom classes are
needed.
2. Compose your layout in a series of managers, subclasses of
layout.managers.root.LayoutManager
, such as
layout.managers.margins.PaddedMarginsLM
, which will position the
correct piece of content in the correct position on the page.
3. Render your layout by calling the
layout.managers.root.LayoutElement.render()
method of the manager at the
top level of your hierarchy. This will render all its children.
1.2. Step By Step¶
The above steps will now be considered in more detail.
1.2.1. Define Classes¶
Classes should subclass layout.managers.root.LayoutElement
,
and override two methods: get_minimum_size()
should return a
layout.datatypes.position.Point
instance, which specifies the
smallest size this item can be rendered at; and render()
which takes a
layout.datatypes.position.Rectangle
instance as the location for its
rendering, and should perform the necessary drawing.
Both of these methods additionally take a data dictionary, which can contain any additional information about the render that is required.
1.2.2. Compose Your Layout¶
To compose your layout, select appropriate managers and create a data
structure from their instantiation. By convention, all managers take
either a single child, or a list of their children (depending on
whether the manager accepts one or more children) as the last element
in their constructors. The most notable exception to this is the
layout.managers.grid.GridLM
class, which needs extra data on
each child, so expects you to call its
layout.managers.grid.GridLM.add_element()
method for each child
you wish to add.
A sample composition might be:
from layout.managers import *
top_level_manager = margins.MarginsLM(
10*mm, 10*mm, 10*mm, 10*mm,
element=transform.ScaleLM(
element=directional.HorizontalLM(
margin=10*mm,
vertical_align=directional.HorizontalLM.ALIGN_MIDDLE,
elements=[
MyElement(a),
MyElement(b)
]
)
)
)
Which is two MyElement
instances (I assume these are defined
by you) side by side
(layout.managers.directional.HorizontalLM
) on a page with at
least 10mm margins all around
(layout.managers.margins.MarginsLM
). If the two elements are
too large to fit in this space, then they will be scaled down, keeping
their relative proportion, until they can fit
(layout.managers.transform.ScaleLM
). Compositions can get
much more complex, and may have to be assembled in stages.
1.2.3. Create the Output¶
With the top level manager created, we can build our PDF by calling
its render()
method. Assuming we’re using Report Lab, we could
do this manually:
canvas = Canvas(filename, papersize)
output = rl_utils.ReportlabOutput(canvas)
top_level_manager.render(Rectangle(0, 0, *papersize), dict(output=output))
canvas.showPage()
canvas.save()
Or we can rely on the utility functions in the layout.rl_utils
module:
canvas = Canvas(filename, papersize)
rl_utils.render_to_reportlab_canvas(canvas, papersize, top_level_manager)
canvas.save()
or even shorter:
rl_utils.render_to_reportlab_document(filename, papersize, top_level_manager)
Similar methods exist for the Cairo renderer. Cairo uses a different
coordinate system, however, so it is not usually practical to use the manual
approach unless you reconfigure the coordinate system manually. See the implementation of cairo_utils.render_to_cairo_context()
for details.