I. First steps

Let's start with the initial parent element that we will extend in this tutorial: a rectangle colored in grey. We configure the element with a static extent where width is set to 500 and height to 300.

BlElement new
   "change fill paint of the shape to light gray"
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   "tell element to have static size"
   extent: 500@300;
   openInWorld

Code snippet above produces the following element:

An element from "First steps"

II. Adding children

Next we add two children (red and blue) with static extent to the parent element. As we did not specify any layout strategy for the parent element this element has the default layout strategy: BlBasicLayoutStrategy. This layout strategy simply positions all children in the top left corner.

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   extent: 500@300;
   "add red child with static size"
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      extent: 200@100);
   "add blue child with static size"
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      extent: 100@200);
   openInWorld
5-14

Code snippet above produces the following element:

An element from "Adding children"

III. Horizontal linear layout

To create a horizontal linear layout we need to send the message #horizontal to the class BlLinearLayout. If we only make this change there will be an error during rendering, as whenever a parent element has a horizontal or vertical linear layout the children must have as layout parameters an instance of BlLinearLayoutParams. This solution is needed as every layout requires different types of parameters. Now the children elements are rendered from left to right starting from the top left corner.

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   extent: 500@300;
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      extent: 200@100);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      extent: 100@200);
   openInWorld
4,9,14

Code snippet above produces the following element:

An element from "Horizontal linear layout"

IV. Matching parent height

Often we want a children element to match the height of the parent element. Right now the blue child has a fixed height. To make it match the height of the parent element we need to configure its layout parameters using #layoutParamsDo:. When working an instance of BlLinearLayoutParams we can configure its vertical and horizontal behavior independently. In this case we want the blue element to have a fixed width of 100 and match the vertical hight of the parent element (#matchParent).

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   extent: 500@300;
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      extent: 200@100);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 100.
         lp vertical matchParent ]);
   openInWorld
15-17

Code snippet above produces the following element:

An element from "Matching parent height"

V. Matching parent height and width

To make the blue element fill all available space to the right we can also configure its horizontal layout parameter using #matchParent. Also for the parent element instead of setting its width and hight using #extent: we can set it by configuring its layout parameters using the #exact: message

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      extent: 200@100);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent ]);
   openInWorld
5-7,18

Code snippet above produces the following element:

An element from "Matching parent height and width"

VI. Filling all available space

Now only the red child does not fill all available vertical space. To change this we can use #layoutParamsDo: and configure the vertical property to match the parent height. We still keep the horizontal extent to a fixed size.

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 200.
         lp vertical matchParent ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent ]);
   openInWorld
12-14

Code snippet above produces the following element:

An element from "Filling all available space"

VII. Wrapping parent size to children

Until now the parent element had a fixed size. However that does not have to be the case. If children elements have a horizontal or vertical size that does depend on the parent element, the parent element can wrap its size to that of its children. In this example we make the two children have a fixed width and then the parent element can wrap its width to that of its children. The width of the parent is now 300.

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 200.
         lp vertical matchParent ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 100.
         lp vertical matchParent ]);
   openInWorld
6,13,20

Code snippet above produces the following element:

An element from "Wrapping parent size to children"

VIII. Playing with padding

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300.
      lp padding top: 5; right: 10; bottom: 15; left: 20 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 200.
         lp vertical matchParent ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 100.
         lp vertical matchParent ]);
   openInWorld

Code snippet above produces the following element:

An element from "Playing with padding"

IX. Playing with padding

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300.
      lp padding top: 5; right: 10; bottom: 15; left: 20 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 200.
         lp vertical matchParent.
         lp padding right: 10 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 100.
         lp vertical matchParent ]);
   openInWorld

Code snippet above produces the following element:

An element from "Playing with padding"

X. Playing with padding

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300.
      lp padding top: 5; right: 10; bottom: 15; left: 20 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 200.
         lp vertical matchParent.
         lp margin right: 10 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 100.
         lp vertical matchParent ]);
   openInWorld

Code snippet above produces the following element:

An element from "Playing with padding"

XI. Using weight

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent ]);
   openInWorld

Code snippet above produces the following element:

An element from "Using weight"

XII. Using weight

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent.
         lp weight: 1 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent.
         lp weight: 2 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Using weight"

XIII. Using weight

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutStrategyDo: [ :ls |
      ls weightSum: 4 ];
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent.
         lp weight: 1 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical matchParent.
         lp weight: 2 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Using weight"

XIV. Towards alignment

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Towards alignment"

XV. Aligning children

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200.
         lp vertical alignCenter ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100.
         lp vertical alignBottom ]);
   openInWorld

Code snippet above produces the following element:

An element from "Aligning children"

XVI. Global alignment center

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutStrategyDo: [ :ls | 
      ls alignCenter ];
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Global alignment center"

XVII. Global alignment center left

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutStrategyDo: [ :ls | 
      ls alignCenterLeft ];
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Global alignment center left"

XVIII. Global alignment bottom right

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutStrategyDo: [ :ls | 
      ls alignBottomRight ];
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Global alignment bottom right"

XIX. Priority of global alignment

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutStrategyDo: [ :ls | 
      ls alignBottomRight ];
   layoutParamsDo: [ :lp | 
      lp horizontal exact: 500.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 150.
         lp vertical exact: 200.
         lp vertical alignTop ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 250.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Priority of global alignment"

XX. Wrap content and match parent conflict

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Wrap content and match parent conflict"

XXI. Wrap content and match parent conflict

BlElement new
   shapeDo: [ :aShape |
      aShape fillPaint: Color lightGray ];
   layoutStrategy: BlLinearLayout horizontal;
   layoutParamsDo: [ :lp | 
      lp horizontal wrapContent.
      lp vertical exact: 300 ];
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color red ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal exact: 300.
         lp vertical exact: 200 ]);
   addChild: (BlElement new 
      shapeDo: [ :aShape |
         aShape fillPaint: Color blue ];
      layoutParams: BlLinearLayoutParams new;
      layoutParamsDo: [:lp |
         lp horizontal matchParent.
         lp vertical exact: 100 ]);
   openInWorld

Code snippet above produces the following element:

An element from "Wrap content and match parent conflict"