You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@pivot.apache.org by Bill van Melle <bi...@gmail.com> on 2011/03/17 21:43:55 UTC

The patchwork that is Pivot layout

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?

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> Well, first off, I apologize for the insult.  I really should have chosen a less aggressive subject line.  It is certainly not my intent to insult the Pivot team, which has produced a very impressive system with limited resources.  Nor do I wish to glorify WPF, which I agree is a bloated beast.  But it happens to be a beast with which I am somewhat familiar, and not long ago Chris invited me to discuss things from there or elsewhere that I thought might benefit Pivot, so here I am.

Fair enough. Discussion is always welcome.

> > <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>
> ...
> > Am I missing something?  Is there an easier way?
> 
> I might put the BoxPane in the Border rather than the other way around.
> 
> Well, that wouldn't be less wordy, but I also don't think it works.  The Border would fill the horizontal space.  And even if it didn't, I can't center it, since Border lacks a horizontalAlignment property.

True. To center the border, you would need to put it in a BoxPane.

> You might also consider using TablePane as your outer container instead of BoxPane.
> 
> It's true that I can get practically anything I want with TablePane, but it can be pretty cumbersome.  The equivalent of a vertical BoxPane means adding a columns specification, and wrapping each element in TablePane.Row.  In my particular example, unless I'm missing some trick, it's more like
> 
> <TablePane>
>   <columns>
>     <TablePane.Column width="1*" />
>     <TablePane.Column width="-1" />
>     <TablePane.Column width="1*" />
>   </columns>
>   <TablePane.Row>
>     <TablePane.Filler/>
>     <Border styles="{color:'gray', thickness:4, cornerRadii:10}">
>       <ImageView bxml:id="imgPhoto" styles="{fill:true}"
>         preferredWidth="150" preferredHeight="150" />
>     </Border>
>     <TablePane.Filler/>
>   </TablePane.Row>
>   <TablePane.Row>
>     <Label TablePane.columnSpan="3" styles="{wrapText:true}" 
>       text="...Some long paragraph..." />
>   </TablePane.Row>
>   <TablePane.Row>
>     <TablePane.Filler/>
>     <PushButton buttonData="Press Me" />
>     <TablePane.Filler/>
>   </TablePane.Row>
> </TablePane>
> 
> But that's not quite right, because it ties the width of the imageview to the width of the button -- if the image is wider than the button, the button is stretched to the width of the image, while if the button is wider, the border is stretched to the width of the button, leaving me no longer with a square border.  

It is fairly common to put BoxPanes in table cells to manage alignment. Another option we have talked about is allowing a caller to specify the alignment of a table cell (similar to HTML), perhaps via an attached property such as "TablePane.horizontalAlignment"/"TablePane.verticalAlignment". We decided against it since the same results could be achieved via composition, but of course it is still an option.

> So I really have to split it up into multiple tables:

...

Couldn't you just put the button in a BoxPane rather than in a separate 3-column table?

> * The XAML editor has Intellisense.  

That's a tooling issue though, not an inherent design limitation.

> * There's a visual designer, so in most cases I don't have to run my app to see whether I got it right, or at least close.  

This is also a tooling issue. But I agree that these features are invaluable.

> * The connection between a XAML file and its backing class is handled automagically internally.  

That's largely because XAML is compiled into a class, whereas BXML is loaded dynamically. However, it's not unreasonable to consider "compiling" BXML at some point in the future.

> * Events are a bit simpler.  That's mostly Java's fault, not Pivot's, but it still is a learning issue.  In WPF, if I want to be notified when my control is resized, I add a single method (or even a closure) to the control; I don't have to write a ComponentListener with 11 (!) methods, 10 of which go unused.

Agreed on this point - though you can generally use an Adapter to avoid having to implement every method.

> But if someone were to ask me my recommendation for a framework in which to build a GUI app that they only ever wanted to run on a Windows desktop, I'd have to point them at WPF, sorry.  On the other hand, for cross-platform apps, I *do* recommend Pivot, but it's with a lot of caveats.

That's cool. I'd probably recommend WPF for Windows-only apps myself, if only because the support is likely to be *way* better.  :-)

> So when there are things from WPF that I think would make Pivot more usable, I hope I can bring them up.  Earlier I've mentioned such things as a ScalingPane (something I could really use right now and have no idea how to implement myself) and simpler markup for document spans of text (which you fixed in 2.0.1, thank you).  I often hesitate to do so, lest you feel I'm casting aspersions on Pivot.  I'm probably coming off as way to much of a WPF fanboy as it is, which is unfortunate, since I and my colleagues get mad at Microsoft all the time...

I wouldn't hesitate to continue making suggestions. Overall, the end result is positive.

G


Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> Um, are you aware of the Adapters which are provided for most Listeners with 2 or more methods?  They have minimal/no-op method bodies and are intended to be extended, 
> 
> No, I wasn't.  Eclipse doesn't propose them as suggestions, so it would have taken some exploring to find them.  But I bet that's a Java idiom, right?  

Yeah, sort of. The difference is that .NET uses delegates for listeners, whereas listeners in Java are often defined as interfaces. If a listener interface has more than one method, it is common to provide an adapter class. By convention, Pivot defines these as static inner classes of the listener interface.



Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
Thanks, Chris.

In order to make some of my BXML less verbose, I have subclassed Pivot
> Containers and added certain defaults and custom properties.  One example of
> this is what I called a StripPane, which is simply a subclassed TablePane
> which maintains an ordered list...
>

Cute idea.  I haven't been terribly adventurous in extending Pivot classes,
but I can see how some convenience classes might simplify things.  I tend to
do that in other systems to mold a framework in a direction that I'm
comfortable, so why not here.

I have gone through a few iterations of a BXML viewer tool which simply
> polls a BXML file for changes and then reloads and displays it, or whatever
> errors occurred.
>

That sounds useful for Pivot programmers everywhere!  I'd be happy to
"beta-test" such a thing.


> Um, are you aware of the Adapters which are provided for most Listeners
> with 2 or more methods?  They have minimal/no-op method bodies and are
> intended to be extended,
>

No, I wasn't.  Eclipse doesn't propose them as suggestions, so it would have
taken some exploring to find them.  But I bet that's a Java idiom, right?
 My java experience before coming to Pivot has been fairly lightweight.  I
withdraw my gripe about the weight of events.

Pivot's Listeners seem to follow a naming convention (not sure if it is
> formal or documented anywhere) whereby the class that defines the 'events'
> is used first, followed by a descriptive word categorizing the group of
> events (where applicable) and then the word 'Listener'
> eg
> ComponentMouseButtonListener  <- mouse button events defined at the
> Component level
> TablePaneListener <- events relating to the TablePane model
>

True, but if I look at the javadoc for TablePane, these are a bit scattered.
 I immediately see getTablePaneAttributeListeners and getTablePaneListeners,
then farther down see one inherited set (getContainerListeners,
getContainerMouseListeners), and then another (getComponentClassListeners,
getComponentDataListeners, getComponentDecoratorListeners,
getComponentKeyListeners, getComponentListeners,
getComponentMouseButtonListeners, getComponentMouseListeners,
getComponentMouseWheelListeners, getComponentStateListeners,
getComponentStyleListeners, getComponentTooltipListeners).  The names are
reasonably suggestive of where you'd find any particular event, though
sometimes I have to try a couple.  It would certainly be useful to have some
kind of condensed documentation where you could easily see in one place all
the listener interface methods, all the bean properties, and all the style
properties.

More later.

Re: The patchwork that is Pivot layout

Posted by Chris Bartlett <cb...@gmail.com>.
Bill,

You raise a couple of different points, for now I will just chip in quickly
where I might be of assistance.

On 18 March 2011 06:23, Bill van Melle <bi...@gmail.com> wrote:

> ... not long ago Chris invited me to discuss things from there or elsewhere
> that I thought might benefit Pivot, so here I am.
>
Yep, I certainly feel that highlighting the comparative strengths,
weaknesses and features of Pivot and its 'peers' can be a useful thing, but
as I'm sure you are aware, you are likely to get a better response on any
mailing list when providing constructive criticism in a non-inflammatory
way.  (Apologies if that comes across as patronizing, it is not meant to be)


I am not in a position to look at your BXML right now, but will try to ASAP,
and will reply again then if I have any useful suggestions.

Without wishing to go too far off topic...
In order to make some of my BXML less verbose, I have subclassed Pivot
Containers and added certain defaults and custom properties.  One example of
this is what I called a StripPane, which is simply a subclassed TablePane
which maintains an ordered list of Components and has an orientation
property.  When the orientation property is 'horizontal' the TablePane will
contain a single row, and n columns if there are n components.  Changing the
orientation to 'vertical' will cause the columns and row to be removed,
before a single new column is added, along with n rows.  Along with a 2nd
quick hack (which I can explain another time) to give me full control over
the sizes of the tablepane's cells (absolute/relative -1,n*,n etc) this
essentially gives me an enhanced BoxPane, but without requiring huge amounts
of markup.

Perhaps something like this could simplify things for you without requiring
you to create custom containers from scratch.  The approach works fine for
me but smells hacky and is not ideal. For instance as I simply subclassed
TablePane (through laziness) it is easy to treat the StripPane as a regular
TablePane and mess things up royally.


> * The XAML editor has Intellisense.  That means there are autocompletion
> hints on property names, and easy access to their documentation.  In Pivot,
> I have to be constantly flipping thru the javadoc just to remember how to
> spell things and which components have which properties, and whether it's a
> component property or a style property.  After a while I get better at the
> spelling part (though capitalization sometimes trips me up), but remembering
> which components have what property I'm not fluent in yet.
>
We have discussed the property/style/javadoc side of things before.  I will
try to get a simple tool posted to the list over the next few days which
might help out with that.


> * There's a visual designer, so in most cases I don't have to run my app to
> see whether I got it right, or at least close.  The Pivot plugin for Eclipse
> helps a tiny bit, but only for standalone bxml files, which is a rarity for
> me -- most of the time I have a backing class.
>
I have gone through a few iterations of a BXML viewer tool which simply
polls a BXML file for changes and then reloads and displays it, or whatever
errors occurred.  It has evolved into something a little more complex now,
but even the simple version would work with fine with classes implementing
the Bindable interface, and allowed me to create small, functionaly
independent chunks of BXML with behavior that could be tested by just
loading into the viewer.

* Events are a bit simpler.  That's mostly Java's fault, not Pivot's, but it
> still is a learning issue.  In WPF, if I want to be notified when my control
> is resized, I add a single method (or even a closure) to the control; I
> don't have to write a ComponentListener with 11 (!) methods, 10 of which go
> unused. I can also see all the supported events in a single place in the
> documentation, rather than having to scan thru the javadoc of multiple
> listeners.
>
Um, are you aware of the Adapters which are provided for most Listeners with
2 or more methods?  They have minimal/no-op method bodies and are intended
to be extended, meaning you just override the methods that you actually
need.
http://pivot.apache.org/2.0/docs/api/org/apache/pivot/wtk/ComponentListener.Adapter.html

Pivot's Listeners seem to follow a naming convention (not sure if it is
formal or documented anywhere) whereby the class that defines the 'events'
is used first, followed by a descriptive word categorizing the group of
events (where applicable) and then the word 'Listener'
eg
ComponentMouseButtonListener  <- mouse button events defined at the
Component level
TablePaneListener <- events relating to the TablePane model

We have a JIRA task for creating a custom Doclet which might well include
detailing all the listeners along with properties, attributes, default skin,
styles etc.
https://issues.apache.org/jira/browse/PIVOT-530


So when there are things from WPF that I think would make Pivot more usable,
> I hope I can bring them up.  Earlier I've mentioned such things as a
> ScalingPane (something I could really use right now and have no idea how to
> implement myself) and simpler markup for document spans of text (which you
> fixed in 2.0.1, thank you).  I often hesitate to do so, lest you feel I'm
> casting aspersions on Pivot.  I'm probably coming off as way to much of a
> WPF fanboy as it is, which is unfortunate, since I and my colleagues get mad
> at Microsoft all the time...
>
I don't remember having seen anyone 'shot down' on the mailing lists for
filing JIRA feature requests, bug reports or similar, so I hope you don't
feel too hesitant about posting in the future.  I imagine that many of those
who have posted to the mailing list first did so to report a bug (I did).

As mentioned at the top of my reply - stating that 'framework X achieves Y
by doing Z, but Pivot doesn't do X' is fine.  Hopefully such an email will
take the form of asking if it is possible to achieve X with Pivot and that
will lead to a discussion of whether X is indeed required, can be achieved
another way, whether its inclusion would fit into the Pivot, and how it
might affect compatibility (etc etc).  I'm not suggesting that every feature
request will always be accepted, but any idea should get a fair hearing and
some justification for why it might be rejected.

Chris

Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
Well, first off, I apologize for the insult.  I really should have chosen a
less aggressive subject line.  It is certainly not my intent to insult the
Pivot team, which has produced a very impressive system with limited
resources.  Nor do I wish to glorify WPF, which I agree is a bloated beast.
 But it happens to be a beast with which I am somewhat familiar, and not
long ago Chris invited me to discuss things from there or elsewhere that I
thought might benefit Pivot, so here I am.

> <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>
> ...
> > Am I missing something?  Is there an easier way?
>
> I might put the BoxPane in the Border rather than the other way around.


Well, that wouldn't be less wordy, but I also don't think it works.  The
Border would fill the horizontal space.  And even if it didn't, I can't
center it, since Border lacks a horizontalAlignment property.

You might also consider using TablePane as your outer container instead of
> BoxPane.
>

It's true that I can get practically anything I want with TablePane, but it
can be pretty cumbersome.  The equivalent of a vertical BoxPane means adding
a columns specification, and wrapping each element in TablePane.Row.  In my
particular example, unless I'm missing some trick, it's more like

<TablePane>
  <columns>
    <TablePane.Column width="1*" />
    <TablePane.Column width="-1" />
    <TablePane.Column width="1*" />
  </columns>
  <TablePane.Row>
    <TablePane.Filler/>
    <Border styles="{color:'gray', thickness:4, cornerRadii:10}">
      <ImageView bxml:id="imgPhoto" styles="{fill:true}"
        preferredWidth="150" preferredHeight="150" />
    </Border>
    <TablePane.Filler/>
  </TablePane.Row>
  <TablePane.Row>
    <Label TablePane.columnSpan="3" styles="{wrapText:true}"
      text="...Some long paragraph..." />
  </TablePane.Row>
  <TablePane.Row>
    <TablePane.Filler/>
    <PushButton buttonData="Press Me" />
    <TablePane.Filler/>
  </TablePane.Row>
</TablePane>

But that's not quite right, because it ties the width of the imageview to
the width of the button -- if the image is wider than the button, the button
is stretched to the width of the image, while if the button is wider, the
border is stretched to the width of the button, leaving me no longer with a
square border.  So I really have to split it up into multiple tables:

<BoxPane orientation="vertical" styles="{fill:true}">
  <TablePane>
    <columns>
      <TablePane.Column width="1*" />
      <TablePane.Column width="-1" />
      <TablePane.Column width="1*" />
    </columns>
    <TablePane.Row>
      <TablePane.Filler />
      <Border styles="{color:'gray', thickness:4, cornerRadii:10}">
        <ImageView bxml:id="imgPhoto" styles="{fill:true}"
          preferredWidth="150" preferredHeight="150" />
      </Border>
      <TablePane.Filler />
    </TablePane.Row>
  </TablePane>
  <Label styles="{wrapText:true}" text="...Some long paragraph..." />
  <TablePane>
    <columns>
      <TablePane.Column width="1*" />
      <TablePane.Column width="-1" />
      <TablePane.Column width="1*" />
    </columns>
    <TablePane.Row>
      <TablePane.Filler />
      <PushButton buttonData="Press Me" />
      <TablePane.Filler />
    </TablePane.Row>
  </TablePane>
</BoxPane>

So you can see how I'd really rather have the ability to specify the
alignment (and sometimes size) of most components within their parent.

... WPF/XAML is an enormous beast that, in my opinion, is far more difficult
> to master than Pivot/BXML.
>

I grant you the former without hesitation, but I'd sure have to quibble with
the latter, especially if you're not trying to master the whole "design a
new control template for some widget and have fancy animation on various
mouse events" task, something which I daresay is hard in Pivot, too, and
which most of us rarely have the need for.

* The XAML editor has Intellisense.  That means there are autocompletion
hints on property names, and easy access to their documentation.  In Pivot,
I have to be constantly flipping thru the javadoc just to remember how to
spell things and which components have which properties, and whether it's a
component property or a style property.  After a while I get better at the
spelling part (though capitalization sometimes trips me up), but remembering
which components have what property I'm not fluent in yet.

* There's a visual designer, so in most cases I don't have to run my app to
see whether I got it right, or at least close.  The Pivot plugin for Eclipse
helps a tiny bit, but only for standalone bxml files, which is a rarity for
me -- most of the time I have a backing class.

* The connection between a XAML file and its backing class is handled
automagically internally.  That means I can write code that creates a custom
control by calling the control's constructor in the familiar way, rather
than fumbling with a serializer call, instance variables are automatically
declared for named components, and events named in the XAML are
automatically hooked up in the backing class.  (The second of those is
helped by the @BXML annotation, at least for trusted apps.  The first I
ameliorate by adopting a programming style of hiding the serializer call
inside a factory method of the class.)

* Events are a bit simpler.  That's mostly Java's fault, not Pivot's, but it
still is a learning issue.  In WPF, if I want to be notified when my control
is resized, I add a single method (or even a closure) to the control; I
don't have to write a ComponentListener with 11 (!) methods, 10 of which go
unused. I can also see all the supported events in a single place in the
documentation, rather than having to scan thru the javadoc of multiple
listeners.

Now to get all that, WPF has been around for years longer and is supported
by a huge, paid development team.  I don't expect all that from Pivot.  But
if someone were to ask me my recommendation for a framework in which to
build a GUI app that they only ever wanted to run on a Windows desktop, I'd
have to point them at WPF, sorry.  On the other hand, for cross-platform
apps, I *do* recommend Pivot, but it's with a lot of caveats.

So when there are things from WPF that I think would make Pivot more usable,
I hope I can bring them up.  Earlier I've mentioned such things as a
ScalingPane (something I could really use right now and have no idea how to
implement myself) and simpler markup for document spans of text (which you
fixed in 2.0.1, thank you).  I often hesitate to do so, lest you feel I'm
casting aspersions on Pivot.  I'm probably coming off as way to much of a
WPF fanboy as it is, which is unfortunate, since I and my colleagues get mad
at Microsoft all the time...

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> Has there been any thought to regularizing the patchwork of layout properties in Pivot?  

I don't consider it a "patchwork". A lot of thought went into the design of Pivot's layout system. And for the record, insulting the design of a system that has been developed entirely by volunteers in their spare time is not the most effective way to ask for help.

> 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}">  
>   <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>
...
> Am I missing something?  Is there an easier way?

I might put the BoxPane in the Border rather than the other way around. You might also consider using TablePane as your outer container instead of BoxPane.

> 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.  

We chose not to add such properties to Pivot's Component class because they do not apply to all containers and because they would add complexity to those layout containers that could theoretically support them. We chose instead to create a small set of focused layout containers that could be combined in various ways to achieve a wide variety of layouts.

> This is an area where WPF seems much more organized to me.  Instead of Pivot's incomplete set of choices...

Again, insulting. And for what it's worth, I'm not sure I'd hold up WPF as an example of good design. Sure, there are a lot of great ideas in there, but WPF/XAML is an enormous beast that, in my opinion, is far more difficult to master than Pivot/BXML.

G



Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
>>> At the moment, the "fill" style of BoxPane is doing double duty.
>>> It means two things for a vertical boxpane
>>> (1) make the component fill the available width if the component is smaller than the boxpane width
>>> (2) if the components preferred width is greater than the available width, cut off the component.
>> Actually, in #2 the component isn't simply clipped to the box pane's width - it is given its constrained preferred height. This gives the component a chance to wrap its content, which wouldn't be possible without the fill style (we need a width to constrain against).
>> 
> Yeah, but we want to give components the chance to wrap even if fill is false, which is not currently the case.

In order to wrap, a component needs a width constraint. The "fill" flag allows us to use the width of the BoxPane as this constraint. Otherwise, how would we know what the wrap width should be? The only other way to do it would be to assign an explicit preferred width to the component.

>>> Border could do with having alignment and fill styles, which is a fairly straightforward change and would make this
>>> class more useful.
>> It could, but I'm not sure how much value that might really offer. How often do you want to put something in a border that doesn't completely fill the internal space of the border? Probably not that often, and when you do, you can use BoxPane, TablePane, ScrollPane, etc.
>> 
> Alignment and fill would affect how the bordered component sits within the space allocated by the parent container. So
> if I wrap a component in a border and put it inside something else, I don't necessarily want it to fill the space within
> it's parent.

That sounds similar to what Bill described. But, as I mentioned earlier, Pivot doesn't define horizontal or vertical alignment properties on the Component class. Layout customization properties are defined by the container, not the child component. The only input a child component has into the layout process is preferred size.

Re: The patchwork that is Pivot layout

Posted by Chris Bartlett <cb...@gmail.com>.
I had a similar idea a while ago after some struggles with ScrollPanes.  I
was thinking of a repository of sample layouts, possibly with an associated
app to browse them.  Something along the lines of ComponentExplorer, only
for layouts, so a LayoutExplorer if you will.

Each layout example needn't be much more than a short description,
screenshot and BXML file, but the screenshot/thumbnail could be
automatically generated once the BXML had been rendered.

A complimentary set of populated, sample components could be supplied as
BXML files to be included (bxml:include) into the layouts in order to
quickly visualize/prototype various scenarios. Think of them as a kind of
Pivot Component 'Lorem Ipsum' library.

Via some simple placeholders in the layout BXML files, the LayoutExplorer
tool to could allow the user to quickly swap in various sample Components
described above, or their own files.

While this might be nice to have, I can now generally hack together my
layouts without too much hassle, so couldn't justify the effort to get a
prototype together.

Chris

On 18 March 2011 22:36, Roger Whitcomb <Ro...@rbwhitcomb.com> wrote:

> Could I make a suggestion here?  Could someone undertake to make a page on
> the website (maybe part of Tutorials) that has a number of common use cases
> (such as Greg is citing here) that has worked out BXML code that implements
> each use case. Such a page could help reduce the number of
> questions/complaints about layout.  My apologies if someone has already done
> this and I just missed it.
>
> ~Roger Whitcomb
>
> Sent from my iPhone
>
>
> On Mar 18, 2011, at 7:41 AM, Greg Brown <gk...@verizon.net> wrote:
>
>  In order to wrap, a component needs a width constraint. The "fill" flag
>>>> allows us to use the width of the BoxPane as this constraint. Otherwise, how
>>>> would we know what the wrap width should be? The only other way to do it
>>>> would be to assign an explicit preferred width to the component.
>>>>
>>>>  In layout(), we have a width constraint we could use, which is the
>>> width that has been allocated to us.
>>>
>>
>> How is that different from the current behavior? That's exactly what
>> "fill" does.
>>
>>  That sounds similar to what Bill described. But, as I mentioned earlier,
>>>> Pivot doesn't define horizontal or vertical alignment properties on the
>>>> Component class. Layout customization properties are defined by the
>>>> container, not the child component. The only input a child component has
>>>> into the layout process is preferred size.
>>>>
>>>>  ImageViewSkin and LabelSkin already have "child" properties like this.
>>>
>>
>> Maybe I misunderstood your suggestion:
>>
>>  Alignment and fill would affect how the bordered component sits within
>>>>> the space allocated by the parent container.
>>>>>
>>>>
>> What is "the parent container" in this case? If it is the Border itself,
>> then yes, those properties would be consistent with ImageView, Label,
>> Border, etc. But that brings me back to my previous point - I don't think
>> the use case for customizing alignment within a Border is particularly
>> strong. There are two primary use cases for a Border:
>>
>> 1) You want the content to fill the border's bounds, and you want the
>> border to grow/shrink with the content's preferred size.
>>
>> 2) You want the border to have some fixed size, and you want the content
>> to be scrollable if it exceeds the size of the border.
>>
>> In case #1, an alignment style would be useless since it would always be
>> ignored. In case #2, you'll need to put a scroll pane in the border and make
>> the actual content a child of the scroll pane, so the alignment styles would
>> be ignored here too.
>>
>>
>>
>>

Re: The patchwork that is Pivot layout

Posted by Roger Whitcomb <Ro...@rbwhitcomb.com>.
Could I make a suggestion here?  Could someone undertake to make a  
page on the website (maybe part of Tutorials) that has a number of  
common use cases (such as Greg is citing here) that has worked out  
BXML code that implements each use case. Such a page could help reduce  
the number of questions/complaints about layout.  My apologies if  
someone has already done this and I just missed it.

~Roger Whitcomb

Sent from my iPhone

On Mar 18, 2011, at 7:41 AM, Greg Brown <gk...@verizon.net> wrote:

>>> In order to wrap, a component needs a width constraint. The "fill"  
>>> flag allows us to use the width of the BoxPane as this constraint.  
>>> Otherwise, how would we know what the wrap width should be? The  
>>> only other way to do it would be to assign an explicit preferred  
>>> width to the component.
>>>
>> In layout(), we have a width constraint we could use, which is the  
>> width that has been allocated to us.
>
> How is that different from the current behavior? That's exactly what  
> "fill" does.
>
>>> That sounds similar to what Bill described. But, as I mentioned  
>>> earlier, Pivot doesn't define horizontal or vertical alignment  
>>> properties on the Component class. Layout customization properties  
>>> are defined by the container, not the child component. The only  
>>> input a child component has into the layout process is preferred  
>>> size.
>>>
>> ImageViewSkin and LabelSkin already have "child" properties like  
>> this.
>
> Maybe I misunderstood your suggestion:
>
>>>> Alignment and fill would affect how the bordered component sits  
>>>> within the space allocated by the parent container.
>
> What is "the parent container" in this case? If it is the Border  
> itself, then yes, those properties would be consistent with  
> ImageView, Label, Border, etc. But that brings me back to my  
> previous point - I don't think the use case for customizing  
> alignment within a Border is particularly strong. There are two  
> primary use cases for a Border:
>
> 1) You want the content to fill the border's bounds, and you want  
> the border to grow/shrink with the content's preferred size.
>
> 2) You want the border to have some fixed size, and you want the  
> content to be scrollable if it exceeds the size of the border.
>
> In case #1, an alignment style would be useless since it would  
> always be ignored. In case #2, you'll need to put a scroll pane in  
> the border and make the actual content a child of the scroll pane,  
> so the alignment styles would be ignored here too.
>
>
>

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> But that's exactly my point.  TablePane has an implicit "fill" behavior in each of its cells.  True, it figures out the size of a "-1" row or column by taking the maximum of the preferred sizes of its elements.  But once it's determined the row/column size, either that way or by using the TablePane size declarations, it forces *everything* in the row/column to "fill" the orthogonal dimension, totally ignoring any preferred sizes given.  Hence, my question, "Would it make sense for an explicit preferred width/height on a component to trump fill?"

Ah, OK. I understand the question now. But I don't think that an explicitly set preferred size should be treated any differently than a default size. That establishes a precedent for inconsistency and might create more problems than it solves. I think it would be preferable to simply add support for alignment to table cells.

> since you think of alignment as a style property, I can't even propose having an attached property to handle that.

That's a good point - though I think in this case an attached property might be OK.

> A vertical BoxPane with fill=true is perhaps a more compelling usage case.  It would be nice if I could have such a pane fill, so that my paragraphs of text could wrap, but still be able to not have other components stretched to the full width of the pane, as I was trying to achieve in my original example but was forced to wrap in a BoxPane to kill the fill.

I understand the motivation. But it still comes back to the same question - how do you know which components should wrap (i.e. be "filled") and which shouldn't? You'd need some way to specify that.

You might be able to use attached properties to control alignment on a per-component basis. But that would be a pain when you know you want all components to use the same alignment (probably the more common case, at least for box panes). The current solution allows you to manage alignment of each component by nesting box panes, but you can still manage the overall alignment with a single style.

I'm not trying to suggest that the current implementation can't be improved - just that there are some design challenges to be considered when thinking about how to improve it.

G


Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
>
> > Why does TablePane override the preferred size of the Border element?
>
> Because you gave the first column and row an explicit size. Try removing
> width="100" and height="80" (or replace them with width="-1" and
> height="-1"). That will tell the column and row to use their default sizes.


But that's exactly my point.  TablePane has an implicit "fill" behavior in
each of its cells.  True, it figures out the size of a "-1" row or column by
taking the maximum of the preferred sizes of its elements.  But once it's
determined the row/column size, either that way or by using the TablePane
size declarations, it forces *everything* in the row/column to "fill" the
orthogonal dimension, totally ignoring any preferred sizes given.  Hence, my
question, "Would it make sense for an explicit preferred width/height on a
component to trump fill?"

I used TablePane as an example, because it has that implicit fill behavior I
mentioned, not controllable by the user.  But it's not the most compelling
usage case, since if I wanted a cell's content not to fill, I would most
likely also want to specify how the content should be aligned within the
cell, something I can only do today by wrapping it in a BoxPane.  And since
you think of alignment as a style property, I can't even propose having an
attached property to handle that.

A vertical BoxPane with fill=true is perhaps a more compelling usage case.
 It would be nice if I could have such a pane fill, so that my paragraphs of
text could wrap, but still be able to not have other components stretched to
the full width of the pane, as I was trying to achieve in my original
example but was forced to wrap in a BoxPane to kill the fill.

Another variation on that can be found if you try to extend the Forms
tutorial a bit.  Form does not by default fill horizontally.  But if I
wanted to intersperse explanatory paragraphs of (wrapped) text, or have a
free-form TextArea, I would have to put fill:true on the Form.  And yet I
might still want some of the form fields to remain at a shorter width lest
they look ridiculous (e.g., if zip code got its own line).  This case is a
little more complicated, because the width of (many of) the TextInput fields
is given by a textSize property, rather than a preferredWidth.  But
TextInput must be using textSize internally to infer a preferredWidth when
combined with the style's font size.

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> I'm clearly misunderstanding something here.   Try running this toy example:
> 
> <Window title="Preferred size example" maximized="true"
>   xmlns="org.apache.pivot.wtk">
>   <TablePane>
>     <columns>
>       <TablePane.Column width="100" />
>       <TablePane.Column width="1*" />
>     </columns>
>     <TablePane.Row height="80">
>       <Border preferredWidth="50" preferredHeight="20" styles="{backgroundColor:'blue'}"/>
>       <Label styles="{wrapText:true}"
>         text="Why is the blue box to my left 100px wide instead of its requested 50px, and 80px high instead of 20?" />
>     </TablePane.Row>		
>   </TablePane>
> </Window>
> 
> Why does TablePane override the preferred size of the Border element? 

Because you gave the first column and row an explicit size. Try removing width="100" and height="80" (or replace them with width="-1" and height="-1"). That will tell the column and row to use their default sizes.



Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
>
> So you've just demonstrated the recursive aspect of my question.  If I set
> a preferred size on a component, and stick that component inside a Border,
> the latter now also has a notion of preferred size.  If the Border is then
> placed inside a TablePane cell, why should the TablePane cause it to ignore
> that size?
>
> It doesn't. TablePane also tries to respect the preferred size of its
> cells. But when a TablePane isn't given its preferred size, it can't give
> its children their preferred sizes, either. So it resizes the cells based on
> the cell width and row height properties.
>

I'm clearly misunderstanding something here.   Try running this toy example:

<Window title="Preferred size example" maximized="true"
  xmlns="org.apache.pivot.wtk">
  <TablePane>
    <columns>
      <TablePane.Column width="100" />
      <TablePane.Column width="1*" />
    </columns>
    <TablePane.Row height="80">
      <Border preferredWidth="50" preferredHeight="20"
styles="{backgroundColor:'blue'}"/>
      <Label styles="{wrapText:true}"
        text="Why is the blue box to my left 100px wide instead of its
requested 50px, and 80px high instead of 20?" />
    </TablePane.Row>
  </TablePane>
</Window>

Why does TablePane override the preferred size of the Border element?

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> Hmm, true, given what I have now come to understand about alignment.  On the other hand, I think alignment should to some extent trump fill, though not completely.  E.g., you ought to be able to have alignment=center, which would mean all components are centered and not stretched to the full width, but the width of the BoxPane still should be a size constraint on its children, so that, for example, text could wrap.  

But this is the question I have been asking Noel - without the fill style, how would it know where/when to wrap?

> An "AlignmentPane" might help, but it would be kind of redundant, since it would basically be a box pane that is limited to one child component. I do wonder if maybe providing alignment support for table cells might not be a bad idea.
> 
> Would it make any sense for there to be an attached property of that sort?  E.g., in my original example, I'd have said BoxPane.horizontalAlignment="center" for the 1st and 3rd components.  Oh, wait, alignment is a style property.  (Another source of confusion for me, really.  I get how font and color and such are styles and might change if you had a global style (skin?) system, but alignment?  Well, maybe so.  CSS has it, after all.)

Yeah, that part of the design was inspired by CSS.

> > Were we designing Pivot from scratch, I'd propose no fill property on any container
> 
> The problem is that, without some concept of "fill" (or "justify"), there's no way to determine width or height constraints, so wrapping wouldn't work.
> 
> I didn't mean to suggest that there wouldn't be fill behavior, just that it wouldn't be exposed.  Lots of containers today implicitly fill, while only a few (notably BoxPane) have an explicit property to control it, something which has clearly led to a lot of confusion.  If all containers filled automatically where it made sense, you'd get fewer of those "why isn't my text wrapping?" questions.

Yeah, that's possible. But I'm not sure how it might be done without making BoxPane less useful or introducing some redundant layout behavior. 

> > Given that, then what do preferred width/height really mean, and why should a parent's fill behavior cause those properties to be ignored?
> 
> They are hints to the container. They also help the container determine its own preferred size. For example, a Border will report a preferred size equal to its content's preferred size plus the border thickness, padding, etc. If a Border is placed in a container that respects preferred size, then its content will also be given its preferred size. In all cases, though, Border simply sizes its content to fill its available client area.
> 
> So you've just demonstrated the recursive aspect of my question.  If I set a preferred size on a component, and stick that component inside a Border, the latter now also has a notion of preferred size.  If the Border is then placed inside a TablePane cell, why should the TablePane cause it to ignore that size?

It doesn't. TablePane also tries to respect the preferred size of its cells. But when a TablePane isn't given its preferred size, it can't give its children their preferred sizes, either. So it resizes the cells based on the cell width and row height properties.

> For example, at the moment, there is no doc at all for BoxPane#setFill and BoxPane#setHorizontalAlignment.  Given all the confusion in this thread about those properties, a little javadoc might head off the next round of same.
> 
> Agreed. Any volunteers?  :-)
> 
> If you're suggesting that I'm one, okay, what is the protocol?  My suggestion involved editing a whole bunch of source code.  Do I do that and submit patch files or something?  (And if so, is there anything in Eclipse to make that easy?)

I'd suggest creating a JIRA ticket for it, then do:

diff > pivot_xxx.patch

from the root of the source tree.





Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
>
> > (1) It is a simple way to place a series of components linearly in a
> container.  In that role, it really would be more logical for it to behave
> as if it had fill=true, much like many other containers implicitly do.
>
> While it is common to use BoxPane with fill=true, it is also pretty common
> to use it with fill=false and some alignment values. So I think having
> support for both is handy.
>

Hmm, true, given what I have now come to understand about alignment.  On the
other hand, I think alignment should to some extent trump fill, though not
completely.  E.g., you ought to be able to have alignment=center, which
would mean all components are centered and not stretched to the full width,
but the width of the BoxPane still should be a size constraint on its
children, so that, for example, text could wrap.  In the absence of a fill
property, this would imply an additional default alignment value, call it
"stretch" or maybe even "fill".


> An "AlignmentPane" might help, but it would be kind of redundant, since it
> would basically be a box pane that is limited to one child component. I do
> wonder if maybe providing alignment support for table cells might not be a
> bad idea.
>

Would it make any sense for there to be an attached property of that sort?
 E.g., in my original example, I'd have said
BoxPane.horizontalAlignment="center" for the 1st and 3rd components.  Oh,
wait, alignment is a style property.  (Another source of confusion for me,
really.  I get how font and color and such are styles and might change if
you had a global style (skin?) system, but alignment?  Well, maybe so.  CSS
has it, after all.)

> Were we designing Pivot from scratch, I'd propose no fill property on any
> container
>
> The problem is that, without some concept of "fill" (or "justify"), there's
> no way to determine width or height constraints, so wrapping wouldn't work.
>

I didn't mean to suggest that there wouldn't be fill behavior, just that it
wouldn't be exposed.  Lots of containers today implicitly fill, while only a
few (notably BoxPane) have an explicit property to control it, something
which has clearly led to a lot of confusion.  If all containers filled
automatically where it made sense, you'd get fewer of those "why isn't my
text wrapping?" questions.


> > Given that, then what do preferred width/height really mean, and why
> should a parent's fill behavior cause those properties to be ignored?
>
> They are hints to the container. They also help the container determine its
> own preferred size. For example, a Border will report a preferred size equal
> to its content's preferred size plus the border thickness, padding, etc. If
> a Border is placed in a container that respects preferred size, then its
> content will also be given its preferred size. In all cases, though, Border
> simply sizes its content to fill its available client area.
>

So you've just demonstrated the recursive aspect of my question.  If I set a
preferred size on a component, and stick that component inside a Border, the
latter now also has a notion of preferred size.  If the Border is then
placed inside a TablePane cell, why should the TablePane cause it to ignore
that size?

For example, at the moment, there is no doc at all for BoxPane#setFill and
> BoxPane#setHorizontalAlignment.  Given all the confusion in this thread
> about those properties, a little javadoc might head off the next round of
> same.
>
> Agreed. Any volunteers?  :-)
>

If you're suggesting that I'm one, okay, what is the protocol?  My
suggestion involved editing a whole bunch of source code.  Do I do that and
submit patch files or something?  (And if so, is there anything in Eclipse
to make that easy?)

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> I think the real double duty is BoxPane itself.  
> (1) It is a simple way to place a series of components linearly in a container.  In that role, it really would be more logical for it to behave as if it had fill=true, much like many other containers implicitly do.  

While it is common to use BoxPane with fill=true, it is also pretty common to use it with fill=false and some alignment values. So I think having support for both is handy.

> (2) With its default fill=false, it is a kind of wrapper (maybe the only one in Pivot?) that allows you to position a single component within a "filled" container, much as I do in the example that started this thread.

FlowPane also allows you to do this. The main difference is that FlowPane will wrap, whereas BoxPane does not. FlowPane also doesn't support a fill style. 

An "AlignmentPane" might help, but it would be kind of redundant, since it would basically be a box pane that is limited to one child component. I do wonder if maybe providing alignment support for table cells might not be a bad idea.

> Were we designing Pivot from scratch, I'd propose no fill property on any container

The problem is that, without some concept of "fill" (or "justify"), there's no way to determine width or height constraints, so wrapping wouldn't work.

> Would it make sense for an explicit preferred width/height on a component to trump fill?  Today, if I want my component to fill the space available in its parent, I simply don't specify a size, right?  

It depends on the container you put the component in. StackPane and Border, for example, will always size their children to fill. BoxPane with fill=false will not, nor will FlowPane. TablePane will size each cell component to fill (to the column width/row height of the cell).

> Given that, then what do preferred width/height really mean, and why should a parent's fill behavior cause those properties to be ignored?

They are hints to the container. They also help the container determine its own preferred size. For example, a Border will report a preferred size equal to its content's preferred size plus the border thickness, padding, etc. If a Border is placed in a container that respects preferred size, then its content will also be given its preferred size. In all cases, though, Border simply sizes its content to fill its available client area.

> I second Roger's point that we could use a tutorial on how layout works, and how to think about it.  A less elaborate way to help in this regard might be to document (in the javadoc) many more of the current style properties.  For example, at the moment, there is no doc at all for BoxPane#setFill and BoxPane#setHorizontalAlignment.  Given all the confusion in this thread about those properties, a little javadoc might head off the next round of same.

Agreed. Any volunteers?  :-)

> I notice that Pivot has a barely populated Wiki.  Can anyone contribute to it?  I've been thinking recently that I ought to write up some kind of "Pivot for the WPF programmer" advice.

It's not public, but if you have an account on the Wiki you can be granted access.



Re: The patchwork that is Pivot layout

Posted by Bill van Melle <bi...@gmail.com>.
>
> Also, what you are describing is *not* consistent with Label and ImageView.
> The alignment styles of those components control the alignment of their own
> content, not how they are positioned within a parent container (exactly the
> way the corresponding styles in BoxPane behave).
>

Wow, there's a lot of confusion in this thread, including my own -- I didn't
realize that horizontalAlignment on a BoxPane or Label referred to the
positioning of its contents.  I had been working off a faulty analogy with
WPF there, so my request for a horizontalAlignment for everyone (in
ComponentSkin), which controlled placement within a parent, would be more of
a change than I realized.

In light of that, I agree with Greg that it wouldn't make sense to change
anything about Border.

Noel talks about the double duty of BoxPane's fill property.  I think the
real double duty is BoxPane itself.  (1) It is a simple way to place a
series of components linearly in a container.  In that role, it really would
be more logical for it to behave as if it had fill=true, much like many
other containers implicitly do.  But it's too late for that now -- such a
change would break existing layouts.  (2) With its default fill=false, it is
a kind of wrapper (maybe the only one in Pivot?) that allows you to position
a single component within a "filled" container, much as I do in the example
that started this thread.  Were we designing Pivot from scratch, I'd propose
no fill property on any container (but instead passing to all their children
their size constraints in whatever way makes sense for the container, such
as BoxPane in the orthogonal dimension), and create a different container,
say "Aligner", for role (2).

However, at this point, I'm not sure what would make the current situation
less confusing, except possibly one thing, which I'll rephrase from one of
my earlier questions.  Would it make sense for an explicit preferred
width/height on a component to trump fill?  Today, if I want my component to
fill the space available in its parent, I simply don't specify a size,
right?  Given that, then what do preferred width/height really mean, and why
should a parent's fill behavior cause those properties to be ignored?

I second Roger's point that we could use a tutorial on how layout works, and
how to think about it.  A less elaborate way to help in this regard might be
to document (in the javadoc) many more of the current style properties.  For
example, at the moment, there is no doc at all for BoxPane#setFill and
BoxPane#setHorizontalAlignment.  Given all the confusion in this thread
about those properties, a little javadoc might head off the next round of
same.

I notice that Pivot has a barely populated Wiki.  Can anyone contribute to
it?  I've been thinking recently that I ought to write up some kind of
"Pivot for the WPF programmer" advice.

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> Currently, when a Label is inside a BoxPane, and fill==false, the
> Label will never wrap, which is a little odd, particularly when there
> is available space.
> I want to create a BoxPane, where orientation==vertical and
> fill==false, but components are allowed to size themselves vertically
> within the available width.

Again, how do you propose to do that? You certainly don't want that behavior all of the time - the fill flag allows you to turn it on and off.

> On the Border front, I want to be able create a Border around an
> ImageView, and then place that Border inside a BoxPane, and tell the
> Border that it should not fill the available space, but instead align
> itself within that available space. This is consistent with how Label
> and ImageView work. So really, what I'm saying is that we should
> extend functionality that is available inside Label to Label's that
> are inside a Border object.

Still not understanding. By default, if you put a Border in a BoxPane, it won't fill the available space. It will fill only its preferred size.

Also, what you are describing is *not* consistent with Label and ImageView. The alignment styles of those components control the alignment of their own content, not how they are positioned within a parent container (exactly the way the corresponding styles in BoxPane behave).





Re: The patchwork that is Pivot layout

Posted by Noel Grandin <no...@gmail.com>.
Perhaps I'm not explaining myself clearly.

Currently, when a Label is inside a BoxPane, and fill==false, the
Label will never wrap, which is a little odd, particularly when there
is available space.
I want to create a BoxPane, where orientation==vertical and
fill==false, but components are allowed to size themselves vertically
within the available width.

On the Border front, I want to be able create a Border around an
ImageView, and then place that Border inside a BoxPane, and tell the
Border that it should not fill the available space, but instead align
itself within that available space. This is consistent with how Label
and ImageView work. So really, what I'm saying is that we should
extend functionality that is available inside Label to Label's that
are inside a Border object.

-- Noel.

On Fri, Mar 18, 2011 at 16:41, Greg Brown <gk...@verizon.net> wrote:
>>> In order to wrap, a component needs a width constraint. The "fill" flag allows us to use the width of the BoxPane as this constraint. Otherwise, how would we know what the wrap width should be? The only other way to do it would be to assign an explicit preferred width to the component.
>>>
>> In layout(), we have a width constraint we could use, which is the width that has been allocated to us.
>
> How is that different from the current behavior? That's exactly what "fill" does.
>
>>> That sounds similar to what Bill described. But, as I mentioned earlier, Pivot doesn't define horizontal or vertical alignment properties on the Component class. Layout customization properties are defined by the container, not the child component. The only input a child component has into the layout process is preferred size.
>>>
>> ImageViewSkin and LabelSkin already have "child" properties like this.
>
> Maybe I misunderstood your suggestion:
>
>>>> Alignment and fill would affect how the bordered component sits within the space allocated by the parent container.
>
> What is "the parent container" in this case? If it is the Border itself, then yes, those properties would be consistent with ImageView, Label, Border, etc. But that brings me back to my previous point - I don't think the use case for customizing alignment within a Border is particularly strong. There are two primary use cases for a Border:
>
> 1) You want the content to fill the border's bounds, and you want the border to grow/shrink with the content's preferred size.
>
> 2) You want the border to have some fixed size, and you want the content to be scrollable if it exceeds the size of the border.
>
> In case #1, an alignment style would be useless since it would always be ignored. In case #2, you'll need to put a scroll pane in the border and make the actual content a child of the scroll pane, so the alignment styles would be ignored here too.
>
>
>

Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
>> In order to wrap, a component needs a width constraint. The "fill" flag allows us to use the width of the BoxPane as this constraint. Otherwise, how would we know what the wrap width should be? The only other way to do it would be to assign an explicit preferred width to the component.
>> 
> In layout(), we have a width constraint we could use, which is the width that has been allocated to us.

How is that different from the current behavior? That's exactly what "fill" does.

>> That sounds similar to what Bill described. But, as I mentioned earlier, Pivot doesn't define horizontal or vertical alignment properties on the Component class. Layout customization properties are defined by the container, not the child component. The only input a child component has into the layout process is preferred size.
>> 
> ImageViewSkin and LabelSkin already have "child" properties like this.

Maybe I misunderstood your suggestion:

>>> Alignment and fill would affect how the bordered component sits within the space allocated by the parent container.

What is "the parent container" in this case? If it is the Border itself, then yes, those properties would be consistent with ImageView, Label, Border, etc. But that brings me back to my previous point - I don't think the use case for customizing alignment within a Border is particularly strong. There are two primary use cases for a Border:

1) You want the content to fill the border's bounds, and you want the border to grow/shrink with the content's preferred size.

2) You want the border to have some fixed size, and you want the content to be scrollable if it exceeds the size of the border.

In case #1, an alignment style would be useless since it would always be ignored. In case #2, you'll need to put a scroll pane in the border and make the actual content a child of the scroll pane, so the alignment styles would be ignored here too.



Re: The patchwork that is Pivot layout

Posted by Noel Grandin <no...@gmail.com>.
Greg Brown wrote:
>>>> At the moment, the "fill" style of BoxPane is doing double duty.
>>>> It means two things for a vertical boxpane
>>>> (1) make the component fill the available width if the component is smaller than the boxpane width
>>>> (2) if the components preferred width is greater than the available width, cut off the component.
>>> Actually, in #2 the component isn't simply clipped to the box pane's width - it is given its constrained preferred height. This gives the component a chance to wrap its content, which wouldn't be possible without the fill style (we need a width to constrain against).
>>>
>> Yeah, but we want to give components the chance to wrap even if fill is false, which is not currently the case.
> In order to wrap, a component needs a width constraint. The "fill" flag allows us to use the width of the BoxPane as this constraint. Otherwise, how would we know what the wrap width should be? The only other way to do it would be to assign an explicit preferred width to the component.
>
In layout(), we have a width constraint we could use, which is the width that has been allocated to us. Similarly in
getPreferredHeight(int).
I already prototyped this, so I know it solves Bill's problem. (but I haven't implemented a complete solution yet).

>>>> Border could do with having alignment and fill styles, which is a fairly straightforward change and would make this
>>>> class more useful.
>>> It could, but I'm not sure how much value that might really offer. How often do you want to put something in a border that doesn't completely fill the internal space of the border? Probably not that often, and when you do, you can use BoxPane, TablePane, ScrollPane, etc.
>>>
>> Alignment and fill would affect how the bordered component sits within the space allocated by the parent container. So
>> if I wrap a component in a border and put it inside something else, I don't necessarily want it to fill the space within
>> it's parent.
> That sounds similar to what Bill described. But, as I mentioned earlier, Pivot doesn't define horizontal or vertical alignment properties on the Component class. Layout customization properties are defined by the container, not the child component. The only input a child component has into the layout process is preferred size.
>
ImageViewSkin and LabelSkin already have "child" properties like this. So we have precedent.
I implemented something similar in BorderSkin as an exercise. Pretty straightforward.
 I'm just waiting on the outcome of this discussion to see if I should check it in.

I agree that this is (minor) violation of the DRY principle, but I like my libraries to have some redundancy, especially
when it eases the life of client programmers.

Regards, Noel.



Re: The patchwork that is Pivot layout

Posted by Noel Grandin <no...@gmail.com>.
Greg Brown wrote:
>> At the moment, the "fill" style of BoxPane is doing double duty.
>> It means two things for a vertical boxpane
>> (1) make the component fill the available width if the component is smaller than the boxpane width
>> (2) if the components preferred width is greater than the available width, cut off the component.
> Actually, in #2 the component isn't simply clipped to the box pane's width - it is given its constrained preferred height. This gives the component a chance to wrap its content, which wouldn't be possible without the fill style (we need a width to constrain against).
>
Yeah, but we want to give components the chance to wrap even if fill is false, which is not currently the case.

>> Border could do with having alignment and fill styles, which is a fairly straightforward change and would make this
>> class more useful.
> It could, but I'm not sure how much value that might really offer. How often do you want to put something in a border that doesn't completely fill the internal space of the border? Probably not that often, and when you do, you can use BoxPane, TablePane, ScrollPane, etc.
>
Alignment and fill would affect how the bordered component sits within the space allocated by the parent container. So
if I wrap a component in a border and put it inside something else, I don't necessarily want it to fill the space within
it's parent.

-- Noel.



Re: The patchwork that is Pivot layout

Posted by Greg Brown <gk...@verizon.net>.
> At the moment, the "fill" style of BoxPane is doing double duty.
> It means two things for a vertical boxpane
> (1) make the component fill the available width if the component is smaller than the boxpane width
> (2) if the components preferred width is greater than the available width, cut off the component.

Actually, in #2 the component isn't simply clipped to the box pane's width - it is given its constrained preferred height. This gives the component a chance to wrap its content, which wouldn't be possible without the fill style (we need a width to constrain against).

> Border could do with having alignment and fill styles, which is a fairly straightforward change and would make this
> class more useful.

It could, but I'm not sure how much value that might really offer. How often do you want to put something in a border that doesn't completely fill the internal space of the border? Probably not that often, and when you do, you can use BoxPane, TablePane, ScrollPane, etc.

G


Re: The patchwork that is Pivot layout

Posted by Noel Grandin <no...@gmail.com>.
Hi

If we focus on the use-case at hand, I can see two things that could be improved in Pivot.

BoxPane
---------------
I think part of the problem here is just the way BoxPane works.
At the moment, the "fill" style of BoxPane is doing double duty.
It means two things for a vertical boxpane
(1) make the component fill the available width if the component is smaller than the boxpane width
(2) if the components preferred width is greater than the available width, cut off the component.

I'm not sure about the rationale for doing (2) - Greg, can you remember why we do that?

Either way, it would be beneficial for split (1) and (2) into separate styles.

Border
-------------
Border could do with having alignment and fill styles, which is a fairly straightforward change and would make this
class more useful.

Regards, Noel.

Bill van Melle wrote:
> 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?
>