=== Top of the Swiki === Attachments ===

The AlignmentMorph

Because a lot of the visual stuff is based on geometry, Morphic has provided some container type Morphs to help 'line up' its subMorphs.

As an example,let's build a simple window launcher type of application.

Let's practice first. Execute:

mary := AlignmentMorph new openInWorld.

then:

mary addMorph: ( SimpleButtonMorph new).
mary addMorph: ( SimpleButtonMorph new).
mary addMorph: ( SimpleButtonMorph new).
mary addMorph: ( SimpleButtonMorph new).
mary addMorph: ( SimpleButtonMorph new).

this gives us five buttons all labeled 'Flash'. And they're laid out horizontally. Let's switch that real quick. Ctrl click on the AlignmentMorph to bring up the menu. Select 'orientation...' Currently it's set on horizontal, so let's switch that to vertical. Select 'vertical'. The buttons switch to a vertical alignment! All automagically.

Let's resize the AlignmentMorph to enclose the buttons. Command click the AlignmentMorph, and grab the yellow resize handle. Notice that when you shrink the AlignmentMorph, the smallest you can go is the rectangle that contains all of the buttons.

One of the cool things about Morphic is that the system is live while we're working. You can grab any Morph you see on the screen and inspect, explore, or send messages to it. Let's see how we might use the Explorer.

First select the top 'Flash' button. We do this by Command clicking on the button. The first click brings up the topmost Morph, which is the AlignmentMorph. Do another Command click on the button. Now click on the red menu handle to bring up the Flash buttons menu. From the menu, select 'debug' then 'explore'. At this point, you should have an Explorer open on the screen. Click on the triangle to the left of 'root: ...' to see the contents of the button.

Let's rename the button. Make sure that 'root: a SimpleButtonMorph ... ' is selected (highlighted).

Go to the bottom pane of the Explorer, and type: self label: 'Browser', and do-it (Command D). Notice the name of the button on the screen changes, and the AlignmentMorph changes its size to accomodate this. We could also have done this from the button's menu. Bring up the button's menu, and select 'change label'. And type in the name that you want.

The Explorer is a powerful tool that not only explores the Morphic world, but also allows you to send messages to different objects in the system. Just remember that 'self' refers to the currently selected object in the upper pane.

We want action, and we want it now !!! Select the 'root: a SimpleButtonMorph ... ' in the Explorer. In the lower pane type self target: Browser' and do-it. Now type self actionSelector: #openBrowser and do-it. Now type self actWhen: #buttonUp. Click the triangle on the top line of the Explorer, then again to refresh the browser. The target: should read 'Brower', the actionSelector: should be 'openBrowser', and actWhen: should be #buttonUp. In other words, when the buttonUp event is triggered, we are going to send the message #openBrowser to the class Browser, i.e. Browser openBrowser.

Go up to the Browser button and click it. And up pops a Code Browser !!! Way cool, dude.



In some ways though this is tedious. Let's build a couple of classes to help us out a bit.

You can pick it up here as a changeset: SimpleLaunch.cs

SimpleButtonMorph subclass: #LaunchButtonMorph
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Morphic Documentation example'

" Here are the instance side methods "
mouseUp: evt
  | delay |
  " The oldColor is the button's original color saved in mouseDown: evt "
  delay _ Delay forMilliseconds: 50.
 (self containsPoint: evt cursorPoint )
 ifTrue: [
  1 to: 3 do: [ :i |
    self color: oldColor.   " display the original color "
    self refreshWorld.     " paint the button"
    delay wait.
    self color: (oldColor mixed: 1/2 with: Color white). " make it a light color again "
    self refreshWorld.     " paint the button "
    delay wait. ].
   ].
  self color: oldColor.
  self refreshWorld.
  super mouseUp: evt.

initialize
  super initialize.
  self useSquareCorners.
  bounds _ 0 @ 0 extent: 96 @ 20.
  self setDefaultLabel.
  self color: ( Color lightGray ).
  self borderColor: #raised.
  self borderWidth: 1.

label: aString
 | oldLabel m |
  (oldLabel _ self findA: StringMorph)
    ifNotNil: [oldLabel delete].
   m _ StringMorph contents: aString font: TextStyle defaultFont.
  " self extent: m extent + (borderWidth + 6). "
  m position: self center - (m extent // 2).
  self addMorph: m.
  m lock


AlignmentMorph subclass: #LaunchAlignmentMorph
instanceVariableNames: ''
classVariableNames: ''
poolDictionaries: ''
category: 'Morphic Documentation example'

" instance methods"

initialize
  | button |
  super initialize.
  orientation _ #vertical.
  button _ LaunchButtonMorph new
    label: 'Browser' ;
    target: ( World activeHand ) ;
    actionSelector: #openBrowser ;
    actWhen: #buttonUp.
  self addMorph: button.
  button _ LaunchButtonMorph new
    label: 'Workspace' ;
    target: ( World activeHand ) ;
    actionSelector: #openWorkspace ;
    actWhen: #buttonUp.
  self addMorphBack: button.
  button _ LaunchButtonMorph new
    label: 'Transcript' ;
    target: ( World activeHand ) ;
    actionSelector: #openTranscript ;
    actWhen: #buttonUp.
  self addMorphBack: button.
  button _ LaunchButtonMorph new
    label: 'Change Sorter' ;
    target: ( World activeHand ) ;
    actionSelector: #openChangeSorter: ;
    arguments: #( 1 ) ;
    actWhen: #buttonUp.
  self addMorphBack: button.
  button _ LaunchButtonMorph new
    label: 'File List' ;
    target: ( World activeHand ) ;
    actionSelector: #openFileList ;
    actWhen: #buttonUp.
  self addMorphBack: button.
  self color: ( Color gray ).


" here is a class side method"
openLauncher
^ self new openInWindowLabeled: 'Go' inWorld: World.

Read these classes into your image.

OK, with this stuff in our image, let's talk about some of what's going on here.

We can bring up our Window Launcher by executing: LaunchAlignmentMorph openLauncher. Try it out. A window with five buttons is created and placed on the Squeak desktop. Clicking on one of the buttons brings up the corresponding Squeak window.

Let's go through some of the methods. First up, LaunchButtonMorph#initialize. Nothing special here, we just define how the button is going to look and how big it is going to be. #label: is a little trickier. A button consists of a bordered rectangle and a string. #label: is centering the string inside of the rectangle.

Being interface designers, we added a little 'trick' for the mouseUp code. When the user releases the mouse button, the button flashes 3 times. This is to indicate that the user has made a selection, that is, a positive reinforcement of his action. All modern interfaces do this type of thing. Again, the delay is applied so that it appears
as if something important has happened on faster machines.

Which leads us to LaunchAlignmentMorph. The class method #openLauncher is provided for convenience. There is one instance method, #initialization. The code looks ugly, but is pretty simple. First, we set the orientation to #vertical, and then we add the buttons. We also set the color to gray.

So, add 'em up. 5 methods to build our little launcher. That's pretty good, and we have the spiffy part about the flashing buttons too !!!

Except we kind of skipped over that button initialization code stuff. Who is this 'World activeHand' character ? That sounds like the next chapter.

Worlds and HandMorphs



Jim Benson
jb@speed.net

Morphic Tutorial FAQ