Aliaksei Syrel

Brick for Pharo | Part I - Introduction

Jan 032015

During my work on some projects for Moose and then for Pharo I had to design UI using Morphic framework. It is rather powerful with lots of features and possibilities for a developer. Morphic allows to create any kind of graphic design with any complexity which sometimes leads to overcomplicated solutions with relatively big number of used hacks. After some time of deep playing with Morphic a Brick was born with a goal to simplify creation of complicated and flexible user interfaces. In this and next posts I will try to describe and explain the basic principles of using Brick. What you should know about it:

Brick is a layer on top of Morphic

Morph subclass: #GLMBrick

Brick replaces layouting mechanism

It overrides all necessary method that are used by Morph to layout submorphs

adjustLayoutBounds
"no need in it"
computeBounds
"nothing to compute, everything is already computed"
computeFullBounds
"nothing to compute, everything is already computed"
doLayoutIn: layoutBounds
"we removed morphic layouting mechanism"
fullBounds
^ self globalBounds
layoutBounds: aRectangle
"I'm not a morph anymore"

Layouting mechanism in Brick is very simple, straightforward and explicit. Everything you are interested in is done in one method:

doLayout
  "most of the time you don't want to override this method"
  "nice example to check is GLMLabelBrick>>doLayout"
  self layoutPolicy layout: self in: self brickBounds.
  self subbricks do: [ :each | each isBrick ifTrue: [ each doLayout ] ]

Brick uses local coordinates

Local coordinates allow to reach high performance implementations of scroll panes, translation animations and any other relative transformations. Brick benefits from such coordinate system, as there is no difference between manual positioning of subbricks an using any predefined layout. To work in the Morphic World, Brick can convert its local coordinates to global ones. 

undefined

Brick can't draw outside of its owner

It is useful because developer should not think about clipping and overlapping issues. Also such behavior is natural for our surrounding real word: you can't place a solid thing inside and outside of the box at the same time, ship can't go outside of the sea.

undefined
Brick supports explicit z-index

In most cases support of z-index is necessary. Morphic partially supports it: ordering depends on the index of submorph in the list. But I think it's much easier to change one integer value than swapping submorphs in order to place a submorph on top/bottom dynamically.

undefined

Brick supports advanced theming

Drawing logic could be moved out of Brick to a separate renderer class. They must subclass GLMBrickRenderer. As soon as you implemented custom renderer it can be set using:

GLMBrick>>renderer: aRenderer

Having possibility to customize drawing logic without subclassing will allow us to apply a complicated theme to a Brick as described here. In the future where vector graphics will be a standard for drawing UI in Pharo. Theme developer will be able to not only change static variables as color, font size but also modify a shape.