3.1 A World of Morphs

A bit of introspection reveals how many Morph instances are in use in the running Cuis-Smalltalk system.

PluggableButtonMorph allInstances size
⇒ 288 (1)

Example 3.1: How many buttons?

The previous example asked for one specific type of morph. What about asking for all types of morphs?

Morph allSubclasses inject: 0 into: [:count :aClass |
   count + aClass allInstances size]
⇒ 1558

Example 3.2: How many morphs are operating on the system?

This number, likely different on your own Cuis-Smalltalk system, represents all the objects necessary to operate the system visually. This count changes all the time; new morphs are created, and those no longer necessary are garbage collected regularly. You can play a bit with the system and evaluate this count again.

3.1.1 Tree of Morphs

Any morph can contain other morphs. We already know a LayoutMorph contains several morphs and manages the way they are laid out; this is reflected in the submorphs attribute of each morph. When this collection is empty, it means there are no submorphs. On the other hand, any morph being displayed knows about its owner: the owner attribute of each morph refers to the morph owning it. And as you might expect, the owner morph’s submorphs attribute contains the owned morph as well.

Then what happens when the owner attribute is nil? The morph is simply not visible! This double link between owner and owned is very convenient and necessary for the morph framework in various situations.

For example, while an owned morph may have its own local coordinate system for its drawing operations, it can refer to its owner to determine its global coordinates, from the point of view of the owner or even from the World perspective – simplified for readability.

Morph>>externalizeToWorld: aPoint
"aPoint is in own coordinates. Answer is in world coordinates."
| inOwners |
inOwners := self externalize: aPoint.
^ owner externalizeToWorld: inOwners

Access to the owner is also useful for mundane aspects like style. A morph asks its owner’s color to draw itself accordingly:

MenuLineMorph>>drawOn: aCanvas
| baseColor |
baseColor := owner color.
aCanvas
   fillRectangle: (`0@0` corner: extent x @ (extent y / 2))
   color: baseColor twiceDarker.
...

On the other hand, the owner, depending on its nature, can decide how to manage its submorphs, like a LayoutMorph does by first requesting which submorphs to lay out:

LayoutMorph>>submorphsToLayout
"Select those that will be laid out."
^ submorphs select: [ :m | m visible ]

3.1.2 Halo of Icons

Because everything is an object in Cuis-Smalltalk, every visual part of the system is represented by an object the user can interact with and inspect. The Halo system, which is itself composed of objects, is a special visual tool to learn more about specific Morph instances. It is invoked on any Morph instance by a middle button click; a halo of colored icons then shows up, surrounding the most general selected morph.

Subsequent clicks access more interior submorphs under the mouse pointer, and the halo is then updated accordingly. When pressing the Shift key, the direction of morph selection is changed: the owner of the selected morph is then selected instead.

Each icon gives access to specific actions to operate on the morph.

ch04-haloDescription

Figure 3.1: Halo and descriptions on each icon functions

Some actions need clarification:

We previously noted the submorph and owner relationship among morphs. In a halo, the orange wrench icon at the right gives access to a set of actions to explore these relations; try it!

ch04-haloDebug

Figure 3.2: Actions to explore sub-morph and owner relations

3.1.3 The Special World Morph

In Cuis-Smalltalk, there is a special morph, a WorldMorph instance, representing the top morph of Cuis-Smalltalk:

WorldMorph allInstances
⇒ { [world]}

Example 3.3: There is only one World!

Guess what? It is the only morph without an owner and still visible. Take any morph in the world, invoke its halo, then from the wrench icon, select the menu entry explore morph and browse the chain of owners until you reach the World; you’ll discover it does not have an owner:

ch04-morphOwners

Figure 3.3: The chain of owners of a morph

Execute the following code to experiment on a morph from its inspector:

Morph new ::
   inspect;
   openInWorld

Example 3.4: Create a morph, inspect it and open it in the World

A blue rectangular morph shows up at the top left corner of the Cuis-Smalltalk window. Sometimes, the morph we are playing with is out of sight, or we are not sure where it is; a convenient way to find it is to ask it to flash itself. In the inspector, execute the code self flash.

Any morph knows about its World; in the inspector, execute: self runningWorld. As a World is a kind of Morph, we can flash it too: self runningWorld flash.


Footnotes

(1)

As a reminder, you execute-and-print to get the result printed; otherwise, it is only executed. Use shortcut Ctrl-p (PrintIt) instead of Ctrl-d (DoIt).