Has there been any thought to regularizing the patchwork of layout
properties in Pivot? I'll say more about what I mean below, but first an
example that prompts my message, my nth frustrating instance of "figuring
out how to do layout in bxml":
Suppose I want to display a photo centered in a pane, and put a paragraph of
text under it. I want the photo to display in a 150x150 square, no matter
what its original size or shape was:
<BoxPane orientation="vertical" styles="{fill:true}">
<ImageView bxml:id="imgPhoto"
preferredWidth="150" preferredHeight="150"
styles="{fill:true, horizontalAlignment:'center'}" />
<Label styles="{wrapText:true}" text="...Some long paragraph..." />
</BoxPane>
So far, so good. Now I decide I'd like the photo to have a nice border
around it, so I try:
<BoxPane orientation="vertical" styles="{fill:true}">
<Border styles="{color:'gray', thickness:4, cornerRadii:10,
horizontalAlignment:'center'}">
<ImageView bxml:id="imgPhoto"
preferredWidth="150" preferredHeight="150"
styles="{fill:true}" />
</Border>
<Label styles="{wrapText:true}" text="...Some long paragraph..." />
</BoxPane>
This fails two ways: Border doesn't have a horizontalAlignment style, and
the fill:true on the BoxPane (needed in order for the text to wrap), results
in the preferredWidth being ignored (whether I put it on the ImageView or on
the Border). So I end up wrapping the whole thing in another non-filled
BoxPane:
<BoxPane orientation="vertical" styles="{fill:true}">
<BoxPane styles="{horizontalAlignment:'center'}">
<Border preferredWidth="150" preferredHeight="150"
styles="{color:'gray', thickness:4, cornerRadii:10}">
<ImageView bxml:id="imgPhoto" styles="{fill:true}" />
</Border>
</BoxPane>
<Label styles="{wrapText:true}" text="...Some long paragraph..." />
</BoxPane>
Bleah. And now suppose I want to put a button centered below the text.
Buttons don't have a horizontalAlignment, either, and the BoxPane's fill
style would make it grotesquely wide anyway, so I have to do the same
BoxPane trick with it:
...
<BoxPane styles="{horizontalAlignment:'center'}">
<PushButton buttonData="Press Me" />
</BoxPane>
...
Am I missing something? Is there an easier way?
This is an area where WPF seems much more organized to me. Instead of
Pivot's incomplete set of choices of which components have alignment
properties, and how you specify that a component should fill the available
space, *all* visual components have HorizontalAlignment and
VerticalAlignment properties. The possible values are Left (Top), Center,
Right (Bottom), and Stretch. Stretch is the default, and says that the
component should consume all the space given by its parent in the indicated
dimension. See http://msdn.microsoft.com/en-us/library/ms751709.aspx for
more.
So the WPF for this example is simply
<StackPanel Orientation="Vertical">
<Rectangle x:Name="imgPhoto" Stroke="Gray" StrokeThickness="4"
Height="150" Width="150" RadiusX="10" RadiusY="10"
HorizontalAlignment="Center" />
<TextBlock TextWrapping="Wrap" Text="...Some long paragraph..." />
<Button HorizontalAlignment="Center" Content="Press Me" />
</StackPanel>
(The photo would be shown as a background "image brush" on the Rectangle.)
All WPF elements also have a Margin property, which Pivot calls padding.
Lots of Pivot components actually do have this property, but it's on a
case-by-case basis, not a member of ComponentSkin.
So you see I find the state of "fill" and "alignment" kind of problematic.
Only 4 classes in Pivot have the fill property: ImageViewSkin, BoxPaneSkin,
TerraFormSkin, TerraRollupSkin. The first means something a little
different; the others are containers. Many containers seem to have an
implicit fill=true, e.g., Border, GridPane, TablePane, Expander (in the
horizontal dimension). Why is it implicit in Expander, but explicit in the
very similar Rollup? I think it would be much less confusing if all
containers implicitly filled where it made sense. BoxPane should fill in
the orthogonal dimension; Form and Rollup should fill horizontally. Just
doing that, of course, would leave me no workaround for the shortcomings I
initially described. But I think those shortcomings ought to be addressed
anyway. For example, I ought to be able to center (and not stretch) a
button in a TablePane column without having to wrap it in a component that
"turns off" the width information from above. Also, it's not clear to me
what "preferredWidth" is really supposed to mean, if it's ignored when in a
"filled" container. If I say preferredWidth=100, why should a wider
container expand that width? Doesn't seem very "preferred" to me. I could
see a narrower container shrinking it, but expanding is not so obvious.
Unfortunately, just switching to the WPF scheme would be a breaking change
(e.g., anyone using the "wrap it in a BoxPane" workaround for Pivot
shortcomings would stop working), so I'm not sure what to recommend. I'd
like to see horizontalAlignment and verticalAlignment (as well as padding)
in ComponentSkin, since they pretty much make sense for any component.
There ought to be a way in the skin implementations to have their use
abstracted out in some common code (waves his hands). Adding a value
STRETCH to the enumerations ought not break existing code, though it
wouldn't necessarily make sense for all uses of the type (e.g., the
HorizontalAlignment enum is also used by ScaleDecorator and by text.Block).
Maybe an explicit preferredWidth or preferredHeight in a style should trump
its parents "fill" behavior? Ditto for an explicit horizontalAlignment or
verticalAlignment (but for that to work, you'd certainly need the STRETCH
value to be the default, so you can tell it was explicit).
Any thoughts from the folks who understand the internals of layout?