The only non-trivial aspect when defining a new LayoutPolicy to be used in Morphic is the handling of the associated layout properties.
These properties allow to configure the way a LayoutPolicy arrange submorphs. E.g. the listDirection property in a TableLayout has the possible values #leftToRight, #rightToLeft, #topToBottom and #bottomToTop, allowing to build a row or a column, and also to arrange the submorphs in reversed order in either dimension.
An instance of LayoutProperties is the holder of the set of properties for a morph. This instance is stored not by the LayoutPolicy, but by the morph itself, and it is also modified through Morph methods. The corresponding methods are gathered in the layout-properties method category in the Morph class.
Therefore, for each property to be added to any kind of LayoutPolicy, the corresponding accessors should be added to the Morph class.
The intent of each property is documented in the corresponding setter in the Morph class.
The package Morphic-Layout includes the TableLayout, which requires the definition of some particular properties in addition to the properties being common to all layout policies. Correspondingly, the class TableLayoutProperties is defined, being a subclass of LayoutProperties.
Now, how can a Morph know which kind of layout property holder to instantiate? This issue is handled as follows.
When a common layout property is set to a Morph, it forces the creation of a LayoutProperties instance; the method assureLayoutProperties does the job. E.g.
hResizing: aSymbol
"Layout specific. This property describes
how the receiver should be resized
with respect to its owner and its children."
self assureLayoutProperties hResizing: aSymbol.
self layoutChanged.
If a particular table property is set, then it is a TableLayoutProperties what must be assured. E.g.
cellInset: aNumber
"Layout specific. This property specifies
an extra inset for each cell in the layout."
self assureTableProperties cellInset: aNumber.
self layoutChanged.
Now image that a Morph is set first the hResizing property, and then the cellInset property. When creating the TableLayoutProperties instance, we should keep the value already set to the hResizing property. Let us take a look to the assureTableProperties method in Morph.
assureTableProperties
| props |
props := self layoutProperties.
props == self ifTrue:[props := nil].
props ifNil:[
props := TableLayoutProperties new initializeFrom: self.
self layoutProperties: props].
props includesTableProperties
ifFalse:[self layoutProperties:
(props := props asTableLayoutProperties)].
^props
So we observe that any object representing a holder for layout properties should understand two additional messages: includesTableProperties and asTableLayoutProperties.
To add even more chaos to the situation, let us take a look to the getter for a table-specific property in Morph.
cellInset
"Layout specific. This property specifies
an extra inset for each cell in the layout."
| props |
props := self layoutProperties.
^props ifNil:[0] ifNotNil:[props cellInset].
but ... what if props is a "base" layout properties holder, i.e. does not include the table-specific properties? Aie ... the table-specific property getters are duplicated in LayoutProperties, e.g.
cellInset
"Default"
^0
so that the default value for each table-specific property is duplicated.