links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Rolodex Tutorial
Last updated at 1:42 am UTC on 19 January 2007
Morphic Rolodex

A Morphic Rolodex Tutorial using Direct Manipulation (and Scripting!)

by John Hinsley

Last updated: Tuesday October 09 2001

The whole project is now on Bob's Super Swiki. If you want to skip the tutorial, see Now on Bob's Super Swiki below (right near the bottom) for how to download it

This tutorial relies heavily (at least for the original idea) on Bolot Kerimbaev's Rolodex System but uses direct manipulation and scripting rather than the file in and code manipulation employed by Bolot. It was inspired by Dan Shafer's recent Counter Tutorial (after the publication of my first draft, Dan very kindly chipped in with a series of suggestions for improvements which I've tried to incorporate) and by a drinking session with friends who were variously committed to Java and Visual Basic.

Tünde, Brian and Mark, thanks for the beer and this one's for you!

I'd also like to thank the Squeak community generally for their help, code and for making such a wonderful tool available. Ned Konz, Karl Ramberg and Steve Elkins were especially kind, contributing code and digging me out of some very deep holes.

Please note that I know little about Smalltalk and less about Morphic: at best this tutorial should be seen as the partially sighted leading the blind!

This tutorial was done in Squeak 3.1. If you're using an earlier version, I'd advise upgrading to at least 3.0. It's also done under Linux.

Squeaking Mice

Squeak is a very mouse intensive environment. Like most Smalltalks, it was originally written for 3 button mice. Consequently, those of you running an Operating System which does not support 3 button mice have to combine keyboard actions with mouse actions and, if we had no easy way of referring to these disparate actions, I'd end up having to write: "On Unix do this, on Mac do the other, on Windows do something else, on BeOS do something I can't quite remember", and so on. Fortunately, once upon a time all mice had colour coded buttons, so we can refer to them symbolically thanks to this table drawn up by Andrew P. Black:

Uploaded Image: mouse_table.gif

I'll try and use this reference throughout: if I don't, feel free to e mail me and slap my wrist! (See also FAQ: Mouse Buttons)

While this seems a little confusing, in practice it becomes second nature very quickly.

Getting Started

From Squeak's opening page, red click to bring up the main menu, select open... and from the open.... menu select morphic project. An orange window will appear. Click on its menu and change the title. (Alternatively, you can just highlight and delete the text at the bottom and type in your title directly, hit enter and it'll appear in the top pane.)

Uploaded Image: 1.gif

Click inside the orange pane to enter the project. You'll find yourself inside a blank project.

Depending on how your version of Squeak is set up, you'll either see little flaps at the left, right and bottom of the screen (labelled, respectively, "Squeak", "Tools" and "Supplies") or just a dark orange bar at the extreme bottom right. We want the flaps visible, so, if you can't see them, run your mouse over the dark orange bar to bring it up and click on "Show tabs". I'd suggest that at this point you click on the red Squeak tab at the left, click on the options button and, red clicking on menus make sure that the classicNewMorphMenu option is selected.

For more on the objects tool and its relationship with the new morph menu, take a look here.

From the supplies flap at the bottom, drag a blank BookMorph. Now, drag out a TextMorph ("Abcdef") from the supplies flap. Blue click until the halo appears around the TextMorph (you'll see a little label "text" at the bottom), highlight the "Text for Editing" and delete it. Type in what you want as your field (for example, "Name").

Uploaded Image: name.gif

Now, you could keep dragging TextMorphs out of the supplies flap until all your fields were complete, but it's easier to use the duplicate icon in the halo to do it. (Strictly speaking this is termed a "handle", and although Alan Kay has written "Anyone who writes a really good tutorial (or any other documentation) can use any terminology they like!", or perhaps because of it (!), I'll stick with "handle" from now on.) All you do is click on the green duplicate handle and use the pincers handle to relocate the copy. Very occasionally it's possible for this to go pear shaped, as though you've got one TextMorph on top of another. Just delete it using the X handle.

Uploaded Image: duplicate.gif

(Incidentally, the duplicate handle is very powerful, much more so than this example can demonstrate.) Change the text to whatever you want to call the field. If the field wraps onto a second line and you don't want it to, use the yellow "change size" handle to drag the string out onto one line by moving it to the right. You may need to use the right button again to bring up the halo to move something into a better position using the black "pincers" handle.

Uploaded Image: 2.gif

Now try moving the BookMorph about with its pincers. If any of the fields "fall out" (and I'm unsure as to why this seems to happen to some and not others!) you'll need to embed them. Pick them up and drag them back into place and choose "embed" from each one's red menu handle. You'll be given a choice of where to embed them. aPasteUpMorph is the white background, so that's no use, while Book will embed them as the title of the book. The only choice is page. But now we've discovered how to create a nice title for the book, we may as well use it. Duplicate one more TextMorph, place it anywhere on the book, and change the text to Rolodex. Use the embed menu to embed it in the book, and voila! there it is, nicely centred, too. The BookMorph even makes room for it. At this point, blue click to bring up the world menu and choose "save".

So far we have the labels for the text fields, but no way of entering the text. Guess what we'll use? That's right, blank TextMorphs! So, duplicate one that's already there,delete the entry ("Name", or whatever) entirely, and place it alongside a field label. Use the duplicate handle to make copies, so that every text field has its own blank TextMorph. Here you will need to drag them out to the right with the change size handle. (This time I'm taking no risks and embedding everything, remember, we want to embed it in page, OK?) You should end up with something like this:

Uploaded Image: 3.gif

Thus far we've done no coding, and we don't need to do any coding at this stage. But we still have a working Rolodex! Now, before you do anything else, click the central dot in the grey bar in the book and choose "save as new-page prototype" this is really important! Save again from the World menu (red click outside of the book), and then red click in the grey bars next to the field names (Name, Address and so on) to enter the details for the text fields for one page:

Uploaded Image: 4.gif

Now, at the right of the grey bar at the top of the book is a little diamond icon (a bubble help "more controls" pops up). Click on that and then on the + icon ("add another page") and fill in the name of a friend or two. You'll not only discover that the pages are all there, but that you can use the find dialogue in the book's main menu to find an item.

Our next task is to try and use a button to pop up that dialogue.

Blue click until the book's halos come up and click on the blue eye handle. You'll see a menu of scripts appear. Yellow click the grey menu icon (it will be labelled basic) and pick "miscellaneous".

Uploaded Image: 5.gif


The script we want is called "Book do menu item". Drag this script out onto a convenient place in the world (it will automatically expand to look like the image below) and click on the up and down arrows on the third element until "search for text" appears.

We can test that this script does, indeed, launch the search dialogue by clicking on the yellow exclamation mark at extreme left. Wow!

Uploaded Image: 6a.gif


Now, take a look back at the viewer and you'll see that a new item corresponding to our Book script 1 has appeared. We get our button simply by clicking on the dot to the left of this item and selecting "button to fire this script" from the menu which pops up.

Uploaded Image: 6c.gif


A green button will appear.

Uploaded Image: 6d.gif

We just need to change the label on this script (Search or Find seem the obvious candidates) and, since I like yellow buttons, change the colour, and embed it in the page. You might also like to change the bubble help for something more appropriate. (You'll find a dialogue to do this by clicking on the button's grey spanner Debug handle.)

Test it by pressing on the button and cancel the dialogue. Now we need to undo all the text we've entered to test our searches and from the central dot menu of the book select the page with the Search button in it as "save as new-page prototype". Now, enter some names, and try it out!

Uploaded Image: 7.gif

That's it. You've just programmed a fully functional Rolodex with a search function in less than an hour (considerably less if this wasn't your first or second Morph) without entering a line of code.

Now, I'm not going to tell you that it's a particularly difficult project, or that this is all there is to Morphic (we've been using only a sort of sub-set of Morphic), but I recon that this would take at least twice, and probably three times as long in any other language.

You might like to take a break and maybe investigate some of the other functions available from the main (dot) menu of the book morp. Book morphs (Ted Kaehler did them) are extremely powerful: they'll take just about any other kind of morph and can be saved (wholly or partly) to disk or URL. Soon I'll write up something on the use of Book Morphs for presentations (as a better alternative to Powerpoint and its clones). You can see more examples of their use on Bob's Super Swiki (see below) or on Squeakland which also has some really splendid uses of etoys (the direct manipulation method we've been using).

Putting it in a Window

For our next trick, we'll put the book in a window. We do this simply by opting to do that from the book's red menu handle. Putting morphs into a window is very usefull: it allows us to label them and, by clicking on the circle at top right, to roll them up.

Fortunately the book will auto-embed in the window! Now we just need to change the window's title (again, through the red menu handle). (Note that this looks a little different from the other illustrations: I re-made this one later, after I'd imported a changeset which changed the appearance of the SystemWindow. Ooops!) That's it for now.

Uploaded Image: 9.gif

Don't forget to save your image now, and each time you put a new entry in your Rolodex.

An enhancement: visibility and affordance!

One of the people who responded to the first version of this tutorial was having problems entering text in the empty TextMorphs (the grey bar). I wasn't sure whether this was due to my description of the process (since revised) or an inherent fault in the interface. Now, on the course I'm doing at the Open University we're taught to assess interfaces in terms of visibility, affordance and feedback. I won't go into the details of that (because I tend to get confused between one and the other!), but if we look at the grey bar, it's not at all clear that it will accept focus or that it will take text. The only feedback we get is that if we do get focus on a TextMorph which is blank and start typing, text appears. I messed about (as one must) with some of the other text morphs from the "Add a new morph" menu and finally found ShowEmptyTextMorph (under S in the "from alphabetical list" sub menu). This both allows focus and shows you have it by a flashing cursor. (If you like, the cursor "affords" that we can enter text.)

If you like the sound of this, all you have to do is to delete the blank TextMorphs and replace them with ShowEmptyTextMorphs. It's easier to manipulate a ShowEmptyTextMorph if you actually fill it in with some text. The illustration shows one field completed, some just full of text for the purpose of manipulation/justification, and another with focus (you should just be able to see the green cursor next to "Name") waiting for input. You'll note that I've also changed the font properties in the ShowEmptyText morphs: you do this by highlighting the text and using the three handles at the bottom of its halo.

Uploaded Image: 10.gif

Again, don't forget to embed the ShowEmptyText morphs in the page and to save the page as a new page prototype, and then to save your image.

Onwards and Upwards: adding an email function

Squeak already has a nice little e mailer called Celeste. It's somewhat minimal (folk are working on enhancements such as a mail sorter as I write), but is extremely elegant and just what we need to add a little functionality to our Rolodex.

To take a peek, just call Celeste from the World menu: open..... email reader.

You'll see that Celeste has a "New" button. Try it out and you'll find that this button calls the wonderfully named Mister Postman, Squeak's email editor. (While you're in Celeste you might like to fill in your e mail address and the SMTP and pop 3 servers of your ISP.)

What we need to do now is to find some way of calling Mister Postman from our Rolodex and to get the To: field to contain the text in the ShowEmptyTextMorph for the email field in that page.

Karl Ramberg and Ned Konz both contributed different ways of doing all that. What follows is my documentation of Karl's implementation of Ned's code. Yes, this will involve a degree of coding (scripting is a better term, as we're not going to use the traditional Smalltalk techniques of creating classes and subclasses. or at least, not for a long time yet) but, as (by now) hardened Squeakers, we shouldn't let that put us off.

We'll use the Rolodex with the ShowEmptyText morphs in the examples: if you want to use the other Rolodex, that should not make any difference.

First, use the - icon on the page's grey bar to remove all but one page from the book. The remaining page should not contain any text apart from the Name, Address and so on fields. Save this page as "New page prototype" from the book's central menu (the dot in the middle).

Now we're ready to implement the code.

First, bring up the halo round the blank ShowEmptyTextMorph or TextMorph where the Rolodex has its e mail field and edit its label to Email. This isn't strictly necessary, but it will add a degree of clarity.

Now, we're going to use the same technique we used with the Search button. Click on Email's viewer (aqua eye) handle to bring up a viewer.

From the menu at the very top of the viewer select "add a new script".

Uploaded Image: email_script1.gif

Drag the tile which appears to somewhere where it's convenient to work on. It'll enlarge to look like the image below.

Uploaded Image: email_script2.gif

If you hover your cursor over the square icon a pop up help will appear "toggle between showing tiles and textual code". We want the textual code, so click on that icon. You'll see a little text field open up.

Now, cut and paste the following text in the text field (after the script1 but before the upward arrow and self):

| message |
                message _ 'mailto:', (self costume contents string ).
                message asUrl activate

Bring up the email script's main menu and choose accept. (I'll try and get round to commenting the code later.)

Uploaded Image: email_script3.gif

As before, you'll find that the viewer panel has automagically obtained an item called "Email script1". Click on the little dot immediately to its left and from the menu select "button to fire this script". Pop that button onto the Rolodex. Now, and change the label to something more meaningful embed it in the page, and save the lot as "new page prototype". Now you can fill in a few email addresses and test it! Don't forget to save your image!

Getting the autodial stuff working

Please note that this is only applicable if you have a dialup Internet connection, and it only makes sense if you have a 'phone close by your computer. If you have a phone near you computer and a working sound card, but no modem, you might like to try: Another Way to do Diallup.

We need to test some of this stuff in a workspace. So, either do alt [k] or red click to bring up the World menu and from open..... open up a workspace. I'll do all this in Linux first, but suspect that it'll be similar on other platforms. The first thing to check is that there is a symbolic link between /dev/modem and /dev/ttys(whatever) -- generally you'll have ttyS0 through to 3. Note that this symbolic link is the standard Linux set up if your system uses wvdial or any of the fancy front ends to it (you can test by calling wvdial in an Xterm):

wvdial whatever_the_name_of_your_service_provider_is

While some Linux dialup applications such as kppp don't need the symbolic link, later versions don't seem to object to there being one. Now, to find out if there is a symbolic link, people using kde can just walk through the directory structure (using the house icon at bottom left) and should see something like this:

Uploaded Image: modem_kde.gif

Other window managers and file managers will have their own way of doing things.

If there is no symlink, you can use either kde or the command line tools mknod or ln (man mknod, man ln for details) or you can possibly use a system administration tool (you can certainly use YaST on SuSE).

With that sorted -- and usually it's already sorted -- we're ready to start experimenting with the workspace in Squeak.

paste the following in your workspace (note that in Smalltalk, comments are denoted by quotation marks -- "this is a Smalltalk comment" -- they won't be read and are there only to make the code easier to read):

myPort:= SerialPort new.

myPort openPort: 2. "corresponds to ttyS2 on Linux. Change this to suit your system"

myPort nextPutAll: 'ATDT(put the number you want to dial here and delete this and the brackets!)', 
"ATDT to get the modem to dial, followed by the number" String cr.    "dial"

Now, highlight the lot and Proposal: Better Debugging (2006) (either alt [d] or do it from the yellow mouse menu). Pick up the 'phone. Is it ringing?

This works fine to get my mobile 'phone in the UK, but Ned Konz who did the *nix hacking on SerialPort and who taught me how to use it suggested 'ATDT611#' which may work, or even be essential for people in the U.S. (I know absolutely nothing about 'phones in the U.S.) You can also use:

myPort nextPutAll: String cr.        "hang up"

myPort  closePort.

But with a bit of luck we won't need those in the final version!

Find something which works for you, and, I suggest, save the workspace by naming it something else: maybe "DialUp". Then save from the World menu. If you need the room to work in, you can, of course, always roll up the workspace by clicking on the circle icon at top right of the wiorkspace -- the bubble help reads "collapse this window". We'll use this workspace a lot from now on, and we'll be able to copy and paste tried and tested code.

We'll need, at some point, a dialogue box to check that we're dialling the right number. There are 3 tools to help you find what's appropriate here, all available under open..... from the World menu: the browser, the method finder and message names. I knew we'd need something with "confirm" so I used message names to locate a few classes:

Uploaded Image: message_names.gif

and here you see the results of my running a do it on it in the workspace:

Uploaded Image: confirm.gif

We need this kind of dialogue because we want to link clicking on an area (probably a button) on our Rolodex to trigger a series of events which results in a number being dialled, but we want to give our operator a chance to back out. It would be good if we could insert the number at some point: maybe we can pick up a clue on how to do that from the code Ned wrote to insert the email address in Mister Postman?

If you've not already done so, re-name the ShowEmptyText morphs for the Home Phone and Work Phone (in the meantime I added a new one for Mobile Phone, as everyone seems to have the damn things -- incidentally, if someone has an instruction booklet for a Motorola c520 and can scan it or photocopy it, I'd love to hear from you: I'm still struggling to work out how to use "a simple menu driven interface"!) just as we did earlier with the email under Onwards and Upwards. We'll be following the same procedure here to make a button for each of the telephone numbers. So, please do exactly as we did before, except we'll now use our new code in the text field of the script. (Do it one button at a time.)

With the script's text pane open, paste this into it from the code we wrote earlier and tried in the workspace:

PopUpMenu confirm: 'Do you want to dial this number?'

and accept it.

From the scripts menu, select, button to fire this script and drag the button top a convenient place on the Rolodex (you can enlarge the Rolodex by first bringing up the halos for the page -- not the book -- and using the re-size handle to make the page larger -- the book will grow to match the size of the page -- and then bringing up the halo on the SystemWindow -- you probably named this Rolodex or Super Rolodex -- and re-sizing that). Click on the button and it should bring up the dialogue box we saw earlier. (If not, you probably didn't change the script to fire on Mouse Up rather than Normal.)

Of course, this won't actually dial anything, yet, and it's pretty useless to have a dialogue which just says Do you want to dial this number?. Bear with me, we'll change all that.

Remember Ned's code uses

(self costume contents string )?
Well, it turns out that if we use
PopUpMenu confirm: 'Do you want to dial ', (self costume contents string), '?'.
then we get the number we entered in the relevant phone field returned in the dialogue. Try it now and see.

The next thing we need to do is to link this to the second chunk of code we tried out in the workspace. That's to say, if we hit yes we want the number to be dialled. If you take a peek at the code we saw in the bottom pane of the message names you'll see:

"Put up a yes/no menu with caption queryString. Answer true if the response is yes, false if no." 
So, it looks like we can hang an if true/if false structure off the result of hitting yes or no.

In Smalltalk, these take the form:

(test condition)
[do this]
[do something else]
(But we can completely omit the ifFalse branch if we don't need it.)

So, delete all the stuff in the script's text pane, and copy and paste this in:


| myPort |

(PopUpMenu confirm: 'Do you want to dial ', (self costume contents string), '?')

[myPort:= SerialPort new.
myPort openPort: 2.
myPort nextPutAll: 'ATDT',(self costume contents string), String cr.].
^ self
Please remember that the number at myPort openPort: 2. must be that of the serial port the modem uses on your system.

And accept it.

Give it a go: it should work when you press the button ;-)

Now, all you need to do is to repeat the process (copy and paste from the text pane!) for the other email fields, and we've got a Rolodex which sends emails and autodials.

This is how mine looks now, but there is no right or wrong way for it to appear!

Uploaded Image: new-look.gif

Now on Bob's Super Swiki

The whole project, up to this point, is now on Bob's Super Swiki. To download it, start Squeak, connect to the Internet, open a file list from the World menu and click in the [ ] of the top left pane:

Uploaded Image: bss_pre.gif

Scroll down in the right hand pane and you'll see Bob's Super Swiki, which is a magic place where lots of Squeak projects live.

Uploaded Image: bss_2.gif

Click on that to open up BSS and you'll find this project as Morphic Rolodex001.002.pr. Then just highlight it and from the yellow mouse button menu select load as project.

Uploaded Image: bss_3.gif

And save your image.

If you decide that you'd like the Rolodex to be on your main Squeak desktop, rather than within a project, simply use the blue mouse button to bring up the halo, select the red menu handle, and then copy to paste buffer. Use the yellow mouse button to return to previous project and, once there, red click to bring up the World menu and click on Add a new morph and then from paste buffer.

What's Next?

For our next trick, we'll try and pop up something to warn when we may be phoning someone at an inappropriate time!

For the future.........

So, what remains to be done? I started off with the idea of a tool which would have all the functionality of the Card Index program which came with Windows 3.1 (surely one of the best Windows programs ever!) and in most respects we have that and more. It would be useful to have some way of printing out details to file and to be able to build a distributable version of the project: this would have to have a save function (so we could keep the details) and a way of allowing the user to select which serial port was responsible for the modem. (Tricky!) On the default side, while we have used scripting throughout, the original aim of doing it by direct manipulation has pretty much fallen by the wayside.

Any comments, criticisms or ideas on how to improve the functionality of this little project will be gratefully received, please e mail me.

In the meantime, may the Morph be with you!