Hi,
My main goal of the recent set of changes to containers and layouts was to make
the HTML/CSS/JS side as minimal as possible, letting the browser and friends
take care of things as much as possible. For the most part, I think it works.
But there is an issue that has been bothering me.
Right now, the LayoutBase class sets up event listeners on the layout host to
automatically re-run the layout under certain conditions. The more I think
about this the less PAYG it is and it is also inconsistent how things are
handled.
The layout code is set up to recognize changes in the layout host's size. When
that happens the layout is re-run. That, to me, is a good thing.
The layout code also waits for the initial "childrenAdded" event and if it sees
it, the layout code will set event listeners for size changes on the children.
If you later add children, those new children may not have listeners attached
(this is an inconsistency). It is the responsibility of the app developer to
dispatch a "layoutNeeded" event on the layout host to trigger the layout.
Again, this is inconsistent as a component could dispatch "childrenAdded" while
another component may not.
I see three possibilities here:
1. Do nothing with children (PAYG). The layout code would listen for size
changes to the layout host, but it would not set up listeners on the children.
An application that changes an items size or adds or removes an item will have
to dispatch "layoutNeeded" on the item's (or items') parent. This way you can
change a component frequently and only trigger its layout when the changes are
complete.
2. Do everything (Pay Heavily). The layout code would really try to listen
for all sorts of events on the layout host and respond to them. The cost would
be high however, if a large number of items were being changed inside of a
loop: the layout code would be run for each pass of the loop.
3. Do everything, but wait (Partial Payment). The layout code would do the
same as #2, but allow for updating loops. A number of systems have this:
host.beginUpdate(); /* do a bunch of things */ host.endUpdate(). While the loop
is running the layout would ask the host if it is OK to update and if not, the
layout would not run. Once the endUpdate() was executed, the host would
dispatch a final "layoutNeeded" and the layout would run once.
I am in favor of #1. It is in the spirit of PAYG and if you decided you needed
either #2 or #3, you could extend a layout and build that yourself. Or we could
add it to the Express package or something like that.
In choice 1, changing an item's size trigger's its own layout. If you have a
Group with 100 elements, all of which are Groups themselves, and you were to
resize each sub-Group in a loop, the resize of a sub-Group would trigger its
layout. This is desired behavior. Once that loop has completed, the outer Group
would also need its layout run to account of the newly resized children and
that's where you do: outer.dispatchEvent(new Event("layoutNeeded")); In choice
2 or choice 3, each time a sub-Group was resized, the outer Group's layout
would run for a total of 100 times, which may even cause some of the
sub-Group's layouts to run again, depending on the layout algorithm.
If I were to remove the child event listeners in the layout code, any place
your app or example that counted on the layout running, you would need to add a
dispatch event for "layoutNeeded" if you did not resize the component.
I hope that made sense.
Peter