Last updated at 12:45 pm UTC on 16 January 2006
'The World is my oyster, and I am its pearl' – HandMorph
'No - There is another' – Yoda
'If all the world is a stage, where does the audience sit?' – George Carlin
'Is it Lunchtime yet?' – You and me both
I like snappy quotes. You can always take them way out of context, and spin them around in ways that the original author never intended, or may even be shocked by. But people place special importance on a quote. They place some deep and meaningful significance on them, even if the quote is just pure drivel. People think that a quote is important just because it's a quote.
One of my favorite quotes is, "Fence is the plural of fent". Drop this one on your friends at the next party you go to, they'll really admire your sense of style. By the way, they'll also probably need an unabridged dictionary to look up the word fent when they get home. That will make you appear even more impressive.
I am just going to say this up front, and get it out of the way. A World is a Morph. There. Did you know that Morphs can contain other Morphs, called subMorphs? And that they can exhibit behavior? I figured I'll just say that in one of the first few of paragraphs, and be done with it.
Let's get down to brass tacks. [Cliches are great fun too. But we all know that puns are evil-Ed.] Like Yoda said, "there is another" special object in Morphic other than the HandMorph. And that is the World. Now, a World is a pretty special object. He's very popular in the morph crowd, everyone knows him and he knows everyone. He's special in a way that makes all of the other morphs envy him, something that they can all aspire to.
Remember the part about a Morph having a visual representation? We've kind of just skated over that part, and never really talked about where we physically draw the visual representation of a Morph, or how it actually shows up on the display. Turns out, we draw on things called a Canvas. Canvas is one of those old school objects, it is not a Morph.
We call FormsViewsAndWindows an abstract class, in that we don't actually draw on a physical instance of Canvas. Rather we draw on an instance of a subclass of Canvas, such as a Forms, Views, and Windows or a PostscriptCanvas. Us computer types call those things a concrete subclass.
You're thinking to yourself, I knew it! He's going to make me write the code for NURBs and Bezier curves next! Let me try to clarify this a bit. In other words, a concrete subclass instance is something we can sink our teeth into, in that it actually implements the behaviour specified by the abstract class. So the abstract class is basically there as a shell that tells its concrete subclasses what protocols the subclass has to implement. Protocols is just fancy talkin'. It really means "here is the set of messages that other objects can send me".
I know, you're thinking, "Dude, what are you talking about?" Well, think of it this way. When I want to draw to the screen, I draw to a bitmap called a Form. A Form is what we see on the screen. When I want to draw to a printer, I draw to a Postscript device. Postscript is another one of those things invented at Xerox Parc a long time ago that solved the problem of how to draw graphics to printers, independent of the type of printer you are talking to. Retro, but still cool. But really, my morph friends don't want or care about what they are drawing on. Nope, instead they just draw on this thing called a Canvas, and let the underlying Canvas worry about the details. So a FormCanvas translates this drawing to a Form, and a PostscriptCanvas translates this drawing to the Postscript language. This lets whoever wants the drawing worry about what form the drawing is in. This is a simple but powerful idea that you'll see sprinkled throughout the Squeak image.
After a long (and even I thought somewhat boring) talk about Canvas, I don't think that you'll be surprised to find out that a World has a Canvas associated with it. A World is the Morph that holds the place where all of the other Morphs do their drawing. No wonder all of the other Morphs are so interested in him!
We can explore the current World by executing:
World is defined in the dictionary called ClassBuilder , which means that it is a global variable. It represents the current World of the The Future of Squeak, 1999 we are in.
Towards the end of the Explorer's list, there is an entry called worldState. If we look through worldState, we notice that it has an instance variable 'canvas' and that its value is a FormCanvas. I may try to confuse you, but I wouldn't outright lie. The worldState has another instance variable, called 'activeHand'. That is the current HandMorph active in the World. See, told ya.
We notice that this World is an instance of PasteUpMorph. Looking through the World with the Explorer, we notice that the submorphs of the current World are all of the top level interface units. Mostly system windows and the like. Now here's a little secret. Come closer to the screen. A World is the top dog. All of the Morphs that you see on the screen are subMorphs of the World you are looking at. Yep, the big kahuna, the top banana, the king. Computer folks who have nothing better to do all day than to sit around naming stuff call this the iroot/i of the Morphic World. All other Morphs in the World are submorphs of the World. That's how a World knows everyone who is in the World.
Rather than look much at the nuts and bolts of PasteUpMorph, let's talk about what it does. As you know, the world is a big place, with a lot of stuff in it. And so it is with a Morphic World. A World has a couple of responsibilities. First, it has its visual representation to worry about. As a World pretty much displays everything on the screen, that's pretty important. A big piece of the code is spent just talking to the display and insuring that all of the screen updates are handled correctly. For instance, you know that the pesky HandMorph is always buzzing around, grabbing and carrying things off. And folks are forever opening windows and drawing stuff. Well, it is the responsibility of the World to make sure that all of this is updated on the screen correctly. And a World takes that responsibility very seriously.
The second part of a World is the behaviour that it exhibits. Remember, a World is also a Morph, so has to know about dragging and dropping and all of the other things that Morphs do. So there's some code in there for that. Here's "When the going gets tough, the tough get going" part [Cliches are so much fun]. An important concept that a World implements is time, or what I call temporal processing. Uh, I sit around all day naming things :-) Anyway, we talked earlier about how a HandMorph does event dispatching. It so happens that a World is the one who tells a HandMorph when it is time to dispatch events. A World also controls a basic Morphic concept which is called stepping.
When someone sends a Morph the #startStepping message, the Morph tells the World that it belongs to that the Morph wants to be sent the message #step at a time interval determined by how the Morph answers the message #stepTime. If you can understand that last sentence, YOU should be writing this. Here's an amazing example, culled straight from the image itself. Execute the following in a Workspace. Check it:
| aClock |
aClock _ ClockMorph new.
" the next three lines are optional – we make the clock blue and bigger "
aClock color: Color blue.
aClock font: (TextStyle default fontAt: 5). "We're going to make the clock bigger than normal"
aClock setBalloonText: 'The time of day. If you prefer to see just minutes, check out my menu.'.
aClock startStepping. " turn the clock on "
A magic clock appears on the display !!! We even put in a little balloon that gives us some information when we wave the cursor over the clock.
You're saying to yourself, "Yeah, but this must be a lot of work. Whenever I've done a clock application before, it's been horrible. You have to keep track of every stinking tick of the computers clock ..... ". Here's what I'm saying. Tell all those people who made you do that to pound sand.
Let's look at the code that actually implements this clock.
Select bClockMorph/b in the class pane and execute Command h. This spawns a hierarchy of all of the classes that ClockMorph inherits from. More fancy talkin', doesn't it ever stop? In the <>bHierarchy Browser<>/b, we see that ClockMorph inherits its behavior from StringMorph. We intuitively know what a StringMorph is. It is a Morph that puts a string of characters or text on the screen.
Now, I'm here to tell you that there is not a whole lot of documentation in the Morphic system as it currently stands. And ClockMorph is no exception. Fortunately, the code is simple enough to understand. There are two key methods: #step and #stepTime.
| time |
" Do what I'm supposed to do "
" Build a string with the current time; "
" showSeconds tells us whether to show the seconds on the clock "
time _ String streamContents:
[:aStrm | Time now print24: false showSeconds: (showSeconds == true) on: aStrm].
"I'm a StringMorph, set me to be that string "
self contents: time
"Answer the desired time between steps in milliseconds."
Not too bad. What this says is that when someone calls the bstep/b method, change the ClockMorph to be a string of the current time. #stepTime is equal to one second (1000 milliseconds).
In our example we said aClock startStepping. This told the World (to which the ClockMorph belongs) to begin sending the message #step to the ClockMorph once a second. When the World sends the message #step, the ClockMorph instance changes itself to be the string representing the current time.
The expression self contents: time is one of those behind the scenes types of messages. Basically it changes the contents of the StringMorph to be the string named time, and notifies its owner that it has changed. This bubbles up the submorph tree until it reaches, you guessed it, the World. The World sees that the StringMorph has changed, and goes about fixing that on the display.
Of course a World is not limited to the number of Morphs that it can be animating at the same time. You can have the ClockMorph running at the same time as other animations.
So that's kind of a birdseye view of what a World is and what it does. I think the clock thing is pretty cool. The ClockMorph starts animating itself in response to this temporal input ...
We must be talking about animation now.Morphic Animation_
Jim Bensonjb@speed.netMorphic Tutorial FAQ