
CHAPTER 3 Layout
interface Glyph : FrescoObject {
//...
void request(out Glyph::Requisition);
};
This asks the child to fill out the requisition describing how it wants to be laid out. As shown in figure 3-9, the Glyph::Requisition struct describes, in each dimension, the glyph's desired natural, minimum, and maximum sizes, as well as alignment.
The box, in turn, will need to fill out its own Requisition when its parent calls request() on the box. Figure 3-10 is an excerpt from the Fresco reference manual describing the hbox and vbox operations from the layout kit.

Consider again the simple vbox with three buttons from figure 3-1 above.
Glyph_var vbox = layout_kit->vbox(); vbox->append(button1); vbox->append(button2); vbox->append(button3); Glyph_var margin = layouts->margin(vbox, 15.0); FrescoLib::run(nil, margin);The window from figure 3-1 does not allow a user to resize it. This is because the vbox inside the window returns a requisition that is not flexible. Let's examine this a bit closer by looking how the vbox determines its own requisition along its tiling axis (its Y axis.)
Referring to the explanation in figure 3-10, the vbox computes its natural, minimum, and maximum sizes along its Y axis as the sum of the three button's natural, minimum, and maximum sizes. In this case, since each of the buttons are rigid (with natural = minimum = maximum) the vbox is rigid as well.
When request() is called on the vbox, then, it returns a rigid requisition to its parent. The request information eventually makes it up to the window, and, as a result, the window does not allow itself to be resized by the end-user.
Let's go ahead, now, and make our vbox resizeable by placing some glue around the buttons. Glue is the TeX term for flexible spacing between characters. In Fresco, glue is a glyph that provides flexible spacing between other glyphs.
We'll allow our vbox to be resized vertically, as shown in figure 3-11 by placing some glue above and below the buttons:
Coord fil = layout_kit->fil(); Glyph_var vglue = layout_kit->vglue(0, fil, 0); Glyph_var vbox = layout_kit->vbox(); vbox->append(vglue); vbox->append(button1); vbox->append(button2); vbox->append(button3); vbox->append(vglue); Glyph_var margin = layouts->margin(vbox, 15.0); FrescoLib::run(nil, margin);Let's examine the glue in this example. It was created with these lines:
Coord fil = layout_kit->fil(); Glyph_var vglue = layout_kit->vglue(0, fil, 0);First, the fil() operation returns a value representing an infinintely large coordinate in terms of stretchability. That is, if maximum = fil, then we can think of the glyph as being "infinitely stretchable". To understand the second line, here's the IDL for the layout kit operation returning the vglue:
interface LayoutKit : FrescoObject {
//...
Glyph vglue(in Coord natural, in Coord stretch, in Coord shrink);
};
In other words, we're asking for vglue with zero natural size, infinite stretchability, and no shrinkablity. If we were to look at this glue's requisition, we'd see for the Y dimension: natural = 0, minimum = 0, maximum = fil. This is because maximum is always given by natural+stretch and minimum by natural-shrink.Although the vbox can now be stretched vertically, it cannot be stretched horizontally. In order to do this, we could place the vbox inside an hbox with horizontal glue to the left and right of the vbox. This would allow the vbox to be stretched arbitrarily in either direction.
In fact, our next example does just this. Figure 3-12 (an example borrowed from Paul Calder2) shows a text label and button composed with boxes and glue to form a component that can be stretched both vertically and horizontally. The "springs" in the diagram represent glue. In this diagram, altogether, there is one label, one button, one vbox, two hboxes, three pieces of vertical glue, and three pieces of horizontal glue. 
The code for this component is shown here:
Coord fil = layout_kit->fil(); Glyph_var push_glue = layout_kit->hglue(0, fil, 0); Glyph_var hbox1 = layout_kit->hbox(); hbox1->append(push_glue); hbox1->append(button); Glyph_var tb_glue = layout_kit->vglue(10, fil, 0); Glyph_var between_glue = layout_kit->vglue(5, 10, 0); Glyph_var vbox = layout_kit->vbox(); vbox->append(tb_glue); vbox->append(text); vbox->append(between_glue); vbox->append(hbox1); vbox->append(tb_glue); Glyph_var lr_glue = layout_kit->hglue(10, fil, 0); Glyph_var hbox2 = layout_kit->hbox(); hbox2->append(lr_glue); hbox2->append(vbox); hbox2->append(lr_glue); FrescoLib::run(nil, hbox2);Let's first examine the glue around the perimeter. The two pieces of vertical glue at the top and bottom, as well as the horizontal glue on the left and right are defined as follows.
Glyph_var tb_glue = layout_kit->vglue(10, fil, 0); Glyph_var lr_glue = layout_kit->hglue(10, fil, 0);This perimeter glue has a natural size of 10, a maximum size of 10+fil (it is infinitely stretchable) and a minimum size of 10-0 = 10 (it won't shrink). Note how we are using the glue to create a border of 10 around the components. (Contrast this with explicitly using the margin glyph in figure 3-1.) The perimeter glue has the combined effect of (1) making the component flexible, (2) centering it when the window resizes, and (3) providing a margin. Below, we'll look at a different implemenation of this program that, rather than using glue around the perimeter, instead wraps the vbox in a chain of three monoglyphs which provide the flexibility, centering, and margin.
For now, let's move on and examine the "push" glue inside hbox1. This glue is defined as
Glyph_var push_glue = layout_kit->hglue(0, fil, 0);and has the effect of pushing over the button so that it's right-justified with the label. Why does a glue with natural size 0 push the button right? The answer has to do with stretchability and the way the vbox and hbox layout children.
Referring again to the explanation in figure 3-10, the vbox, which aligns children along its X axis, defines its natural size in the X dimension to be the maximum of the child natural sizes in the X dimension. In our case, this means that the vbox defines its natural size to be the size of the label, because the label is larger than hbox1 (who's natural size is just that of the button.)
The important point is that the vbox is defined to allocate this natural size as the X allocation for each of its children. Thus, hbox1, which requested a natural size equivalent to that of the button, is allocated an X allotment equivalent to that of the label. It is up to hbox1, then, to determine what to do with this additional allotment. It examines the Requisitions of its children and determines that the button is rigid in the X dimension but the glue is not. Since the glue is stretchable, it allocates the extra space to the glue. The result is to right-justify the button.
Finally, let's examine the "between" glue that separates the label from hbox1. We'd like this glue to stretch, but not as fast as the glue around the perimeter. A first attempt might be to specify the glue so it has an initial size of 5 and a maximum size of 10. The idea is that it will stretch, but that it won't stretch beyond 10 points.
Glyph_var between_glue = layout_kit->vglue(5, 10, 0);However, as shown in figure 3-13, this won't work, because even as the window is stretched very big, the gap between the button and hbox1 will not get larger.

Let's examine what causes this problem. The problem is related to how a box divides up its extra allocated space. When a box recieves space greater than its natural size, it allocates the extra space to each flexible component in proportion to that component's relative flexibility. In other words, if the component is relatively flexible, it gets a lot of the extra space; if it's relatively inflexible, it gets just a little. (And if it's not flexible at all, it gets none.)
In our case, the between_glue's relative flexibility is negligible when compared to that of the its infinitely stretchable siblings, the top and bottom glue. Thus the between_glue is given a negligible portion of the extra space--it's all divided up between the top and bottom glue. To remedy this, we can define the stretchability of the between_glue in a relative fashion:
Glyph_var between_glue = layout_kit->vglue(5, fil/10, 0);Now the between_glue will stretch at 1/10'th the rate of the top and bottom glue.
Here are the layout kit operations related to glue:
Glyph glue( in Axis a, in Coord natural, in Coord stretch, in Coord shrink, in Alignment align ); Glyph glue_requisition(in Glyph::Requisition r); Glyph hfil(); Glyph hglue_fil(in Coord natural); Glyph hglue(in Coord natural, in Coord stretch, in Coord shrink); Glyph hglue_aligned( in Coord natural, in Coord stretch, in Coord shrink, in Alignment a ); Glyph hspace(in Coord natural); Glyph vfil(); Glyph vglue_fil(in Coord natural); Glyph vglue(in Coord natural, in Coord stretch, in Coord shrink); Glyph vglue_aligned( in Coord natural, in Coord stretch, in Coord shrink, in Alignment a ); Glyph vspace(in Coord natural);Many of these operations are convenience functions. The hglue() and vglue() operations return glue with zero alignment. The hglue_aligned and vglue_aligned() operations are provided in case you want to set a non-zero alignment. The glue() operation is equivalent to the _aligned() calls, but with the Axis specified explicitly. For example, For example
hglue_aligned(10,10,10, 0.5)is equivalent to
glue(X_axis, 10,10,10, 0.5)Similarly, the call
hglue(10,10,10).is equivalent to
glue(X_axis, 10,10,10, 0.0)The operations hfil() and hglue_fil() returns glue with infinite stretchability and no shrinkability. For example,
hglue_fil(10)is equivalent to
hglue(10, fil, 0)and
hfil()is equivalent to
hglue(0, fil, 0).Conversly, the hspace() operation returns glue with no stretchability. For example,
hspace(10)is equivalent to
hglue(10, 0, 0).Finally, the glue_requisition() simply returns a piece of glue that will request the same requisition as the glue passed in.
Let's examine a different implementation of the component in figure 3-12. Rather than using 3 boxes and 6 pieces of glue, the following code uses just one box and one piece of glue.
Coord fil = layout_kit->fil(); Glyph_var between_glue = layout_kit->vglue(5, 10, 0); Glyph_var vbox = layout_kit->vbox_align_elements(1.0); vbox->append(text); vbox->append(between_glue); vbox->append(button);In figure 3-12, left-justifying the button was achieved by placing the button inside an hbox with stretchable glue. Here, in order to left-justify the button, we ask the layout kit for a special type of vbox--one that overrides the alignment of each child placed inside it. Since we specify
Glyph_var vbox = layout_kit->vbox_align_elements(1.0);we get a vbox which will right-justify each of its children.
In figure 3-12, we had achieved resize and centering behavior by positioning perimeter glue along the top, bottom, left, and right. Here, we achieve resize and centering behaivor explicitly--by wrapping the vbox inside glyph to override alignment, and then wrapping this inside a glyph to override flexibility:
Glyph_var centered = layout_kit->align(vbox, 0.5, 0.5); Glyph_var flexible = layout_kit->flexible( centered, fil, fil /* flexibility: full stretch, full shrink */ );Finally, we wrap the result inside a margin for the border, and put this inside a main viewer and window.
Glyph_var margin = layout_kit->margin(flexible, 10); FrescoLib::run(nil, margin);Well, this seems like a neat implementation, but, as one might imagine, it doesn't work. In this case, when we resize the window, the between_glue does not stop at 10 but stretches infintely. The reason for this is that most layout glyphs--vboxes included--do not attempt to constrain "greater-than-maximum" allocations. In other words, if a span larger than its maximum requisition is allocated, rather than first shortening it to maximum, the vbox will just allocate the full span to its children. It divides it up as it would any allocation, and, in the case of our example, it gives all span in excess of the natural size to our between_glue (the only flexible child) causing the glue to stretch infinitely.
One solution is simply to define the between_glue as rigid:
Glyph_var between_glue = layout_kit->vglue(5, 0, 0);Now, since the vbox does not have a flexible child, it will not attempt to pass on surplus allocation. It simply allocates to each child their natural size, and everything works fine. Having this between_glue be rigid is likely the behavior we would want in real life. But let's assume that someone really does want this glue to stretch. We need another way to prevent the hbox from allocating its "greater-than-maximum" span to the between_glue. Another solution is to intervene and wrap the vbox in a monoglyph that constrains the given allocation to that of its body's maximum. The layout kit, alas, provides no such monoglyph, so we'd need to build this ourselves.
Another approach is to add some infinitely stretchable glue to the vbox. Now, since the vbox would have no maximum, we need not worry about what it does with greater-than-maximum allocations. Adding this glue makes everything work fine. As above, the between_glue is defined relative to the infinitely stretchable glue.
Coord fil = layout_kit->fil(); Glyph_var tb_glue = layout_kit->vglue(0, fil, 0); Glyph_var between_glue = layout_kit->vglue(5, fil/10, 0); Glyph_var vbox = layout_kit->vbox_align_elements(1.0); vbox->append(tb_glue); vbox->append(text); vbox->append(between_glue); vbox->append(button); vbox->append(tb_glue);As a final note on this subject: one might be tempted here to append just one piece of infinite glue, rather than two (for example, append it at the top only) but this would make the vbox "lopsided" and the centering monoglyph would not be able to keep the label and button centered.
Generated with CERN WebMaker