The Making of EllipticalLayout
Last updated at 1:30 am UTC on 17 January 2006
EllipticalLayout is a subclass of LayoutPolicy. It places the first submorph in the center of the layout, and the rest of the submorphs on concentric ellipses around the center submorph. In the future, I plan to make it and ImageLibrary, an application that uses it, available on SqueakMap.
Writing EllipticalLayout and getting it to play nicely with others was challenging for me, a Squeak newbie, so I thought I'd write something up and save other people some effort. If anyone sees something I did wrong or oddly, please edit this page to let everyone know what the right way to do it is.
The first step is to figure out exactly what you want your new layout to look like in terms of where you place the submorphs of a particular morph. I knew I wanted some morphs in the center and some morphs around the edges that look like a collage. This is not specific enough. The key questions for me were:
- How do I make the morph look good, even though I don't know how many submorphs it has, or what size they are?
- How do I tell which submorphs go in the center?
- How do I tell which submorphs go around the edges?
- How do I lay out the morphs in the center?
I built a sample morph so I could try some ideas. This was very helpful. The key things that made the morph look good were:
- Laying the edge submorphs out on arcs that used the same proportions as the cluster of submorphs in the middle.
- Overlapping each edge submorph with its neighbors a little, but not too much.
- Placing about the same number of edge submorphs on the left side as on the right side. This was more important than placing about the same number of edge morphs on the top as on the bottom.
My first thought about determining which submorphs go in the center and which go on the edges was to mark each submorph with some property. But when I thought about how to lay out the center submorphs, I realized that the easiest way to do this was to embed them all in some other morph, and let each application that might want an EllipticalLayout choose how it wanted to lay out its own center.
If there is only one submorph that is special, the easiest way to distinguish it from the others is to put it first in the Collection of submorphs. So, I settled on putting the first submorph in the center and the rest on the edges, rather than marking submorphs in some way.
Code and Debug
A good order to do things in seemed to be:
- deal with bounds issues
Note that self halt doesn't work the way it normally does from inside a LayoutPolicy. The best way I could find to debug was to insert a self halt in only one layout method, then immediately trigger a change in layout so that method gets run. A message about failed system error handling should appear in the upper left corner of the screen. Press enter to get an emergency evaluator, then revert, then exit so the layout & display process can finish. When it does, there should be several normal Halt windows available so you can step through your code.
For me, dealing with bounds issues meant changing Morph>>adjustLayoutBounds, and writing indexForInserting:at:in: meant writing Morph>>closestSubmorphTo:. I suspect that most new LayoutPolicy subclasses will involve changing Morph in some way you don't necessarily expect when planning.
To make my new layout appear in the menus like existing LayoutPolicy subclasses, I had to do several things:
- create an isEllipticalLayout method on both LayoutPolicy and EllipticalLayout
- change Morph>>addLayoutMenuItems:hand:
- create hasEllipticalLayoutString and changeEllipticalLayout on Morph
Obviously, Morphs designed to use one LayoutPolicy will tend to look bad if they are changed to use another layout. I would override changeEllipticalLayout and changeTableLayout, for example, on any Morph you would like to look good using either layout.