A bit of introspection reveals how many Morph instances are in use in the Cuis-Smalltalk living 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 morph?
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 visually the system. This count changes all the time, new morphs are created and ones no more necessary are garbage collected regularly. You can play a bit with the system and evaluate again this count.
Any morph can contain other morphs. We already know a LayoutMorph contains several morphs and manage the way there are layed out; these is reflected in the submorphs attribute of each morph, when this collection is empty it means there is no sub-morph. In the other hand, any morph being displayed knows about its containing owner: the owner attribute of each morph refers to the morph owning it. And as you can expect it, the owner morph 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 depending on the situation.
For example, while an owned morph may have its own local coordinates system for its drawing operations, it can refer to its owner to know about its global coordinates situation, from the point of view of the owner or even from the World perspective – simplified for readiness
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 aspect as the 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. ...
In the other hand, the owner, depending on its nature, can decide how to dispose its sub-morphs, like does a LayoutMorph by first requesting which sub-morphs to lay out
LayoutMorph>>submorphsToLayout
"Select those that will be layout" ^ submorphs select: [ :m | m visible ]
Because everything is an object in Cuis-Smalltalk, every visual part of the system is represented through an object the user can interact with and inspect. The Halo system, designed with objects, is a special visual tool to know more about specific Morph instances. It is invoked on any Morph instance by a middle button click, a halo of coloured icons then shows up, surrounding the most general selected morph.
Succeding clicks accesses 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.
Figure 3.1: Halo of a LayoutMorph
Each icon gives access to specific actions to operate on the morph.
Figure 3.2: Halo and descriptions on each icon functions
Some actions need clarifications:
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!
Figure 3.3: Actions to explore sub-morph and owner relations
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 owner until you reach the World, you discover it does not have owner:
Figure 3.4: 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. Sometime, the morph we are playing with is out of sight, or we are not sure where it is; a convenient way to find is to ask it flashes 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.
As a recall, you execute-and-print to get the result printed; otherwise, it is only executed. Use shortcut Ctrl-p (PrintIt) instead of Ctrl-d (DoIt).