Layout
Layout is the process of determining the locations of figures in a drawing.
This two step process includes marking figures as invalid (needing layout), and
then validating the "branches" of figures that are invalid. Multiple updates to
a drawing can result in multiple figures becoming invalid. To prevent
intermediate states from being displayed to the user, Draw2d provides a deferred
update strategy which integrates layout with native paint requests as well as
figures requesting repaints. The result is that layouts occur all at once,
after which the results are painted.
Figure delegates the task of placing children to their
LayoutManager
. This allows layouts to be swapped and is also just
good separation of concerns. Layouts cannot be shared because they may cache
information about their owner.
Validation
Validation is almost synonymous with layout. A figure that needs to layout is
marked as invalid.
All figures start in the invalid state when
constructed. At some point later when validate()
is called, they mark themselves as valid and perform their layout. After layout,
the figure will then validate its children. Draw2d only uses validate to perform
layouts, but in theory it could be extended to perform any sort of potentially
expensive calculation that needs to be integrated with the update manager.
Preferred Size
Most layouts need to query the children for their size constraints. IFigure
provides methods for querying the minimum, preferred, and maximum sizes. A
figure such as Label will have a preferred size based on its text or icon being
displayed. If a figure contains other figures, then its preferred size will be
based on how it would like to arrange its children. In this case, the size
requests are forwarded to the layout manager.
Hints can be used when querying preferred and minimum size. For example, if
the amount of available width is known, this width can be passed to a figure
which may be wrapping a paragraph of text. The figure would then return the
height and width necessary to wrap the paragraph to the given amount of space.
Changes that cause Layouts
When a figure is changed in a way that affects its preferred size or layout,
it calls revalidate()
. Revalidation is the process of marking
yourself as invalid and requesting revalidate on your parent figure. This
process continues up the parent chain until the root figure (or some validation
root) adds itself to the update managers list of invalid figures. At a later
time, the update manager will go through its collection of invalid figures and
call validate() on them. In some situations, invalid figures may be added or
re-added during validation. This is fine as long as the dependencies do not
result in a never-ending cycle. The following image shows the chain of events:
|
|
A changes happens to Fig 4 that affects its preferred
size. It calls revalidate(), which walks up the parent chain marking
figures as invalid until a "root" is reached which is reported to the
update manager.
|
The update manager validates the invalid branches.
Layout happens top-down. Note the Fig 5 was not invalid, but if Fig 2
changes its size as a result of laying out, the Fig 5 will mark itself
as invalid and get validated as part of the same pass.
|
In the above example, Fig 5 may have its size changed when Fig 2 performs its
layout.
Top-Down Layout
Normally figures layout in a top-down fashion. This means that figure has its
bounds set before it lays out its children. Also, after it places its children,
it then calls validate() on them in case their size changed, making them
invalid. This is the same way that Composites work in SWT.
Special-Purpose Layout Techniques
In some cases, the top-down process is modified. A common example is figures
whose bounds must wrap around the bounds of their children.
Connections and "freeform" figures are examples
of this behavior. In these cases, the figures still layout children first, but
they determine their own bounds afterwards. Note that the children are not
positioned relative to the bounds since it is unknown during layout. This also
implies that the figures do not use local coordinates for their children.
The other special layout case is found in the text package. Text figures must
layout in two steps. First, they contribute fragments into paragraphs or blocks.
These fragments may get reordered for bidirectional text. Also, their baselines
and the overall alignment of each line may also be adjusted. The end of a line
or block may only occur after a figure has finished its layout. So, the second
layout pass is simply a finalization step in which the figures are told to now
update their bounds based on their final fragment locations. Understanding this
layout is no necessary for using the text package, but it does help in
appreciating some of the problems solved by Draw2d's approach to layouts and
coordinate systems.