Worlds and HandMorphs
Last updated at 12:45 pm UTC on 16 January 2006
By Jim Benson (firstname.lastname@example.org)
You are not going to believe what I am about to tell you. Flat out, won't believe it. Nope, can't be that way, you'll say. No, you're wrong, you'll think. He's a stinkin' liar.
The subject, HandMorph and the World. HandMorph first.
A HandMorph is a Morph. See, I told you. You don't believe me. Let me plead the case. Bring up a Browser on HandMorph. Look at all those methods! Look at the event handling section! Look at the 'world menu commands'! This can't be a Morph. A Morph is friendly and simple, fun to be with, just like a new puppy. Just define a few methods and we're doing magic. This thing's a mess.
You're not going to like my answer. A HandMorph is simple. No, really ...
The HandMorph represents the cursor. It's that thing you see when you move the mouse around on the screen, your center of interaction in the graphical environment. The cursor on the screen is the visual representation of the Morph. Whew, I guess that fell into one of the things we know about Morphs.
Most of the code is for the behavior of the HandMorph. There are three main behaviours that a HandMorph exhibits. If you think about it, the cursor has a lot of work to do. It has to do things like figure out when the mouse moves, if the button for the mouse goes down, if there is a keyboard button down when the user clicks the mouse, and so on. As software folks, we know just to treat the whole thing with total disdain. Just practice saying things like, "Oh, that's HARDWARE stuff". Say it derisively, like it's below you your station in life to even look at it. It helps to add a little tone of contempt at the same time. Just like all the really good software people do.
The second thing that the cursor does is report to other Morphs about both its presence and actions of the underlying hardware. One of the big behaviors that HandMorph implements is event dispatching. HandMorph is responsible for sending out things like #mouseDown:, and #mouseEnter: to the other kinder, gentler morphs. This is a little more complicated then it would first appear, because not only does HandMorph have to dispatch the events, but he has to figure to whom the events must be dispatched. And the he is also responsible for handling the keyboard!!! He's a man's Morph. A HandMorph is like a John Wayne character, bigger than life and able to control an entire world by his lonesome. A lot of the code is just general housekeeping work, keeping track of where everybody is and handling the special cases when some other Morphs have their fancy pants costumes on. Those fancy Morphs don't like getting their costumes wrinkled, but the manly HandMorph isn't afraid of getting some dirt under his fingernails.
The third behavior that HandMorph exhibits is grabbing and dropping. Let's do an example. Execute:
RectangleMorph new openInWorld
A RectangleMorph appears in the upper right hand corner of the Squeak window. Now, click and drag the rectangle. Another Wowie !!! By the way, you can do this with almost any morph by holding down the command key while click dragging. This helps with Morphs who have behaviors associated with mouse down events. Notice that when you drag the rectangle, the cursor has changed to a non-highlighted visual state. This is one of those user feedback feel goods. And you're saying to yourself, "Hey, what's the big deal about moving a rectangle around?"
Take a moment to yourself and try to figure out how this works before going on.
You're smart, you know the answer. Let's say we want to grab our rectangle and drag it somewhere. The cursor wanders over to the rectangle. When the HandMorph ( this is in the HandMorph #handleMouseDown: method ) processes a mouseDown event, it tells the Morph that is about to be grabbed and then, incredibly enough, grabs it. And how does it do that? Well, in my best drone, a Morph can hold other Morphs, called subMorphs. So the HandMorph simply grabs the morph that he is pointing at from whoever is holding it and does #addMorphBack: which adds the Morph to the cursor. In other words, the Morph becomes a submorph of the HandMorph cursor. Remember how we talked about a composite? Now the cursor and the Morph that he picked up are treated as one unit. So when you move the cursor when you have something grabbed, the object moves with you, because the Morph is now part of the structure of the cursor. Of course, the grabbed Morph can be a composite too.
Now that the cursor has the Morph, the user may 'drop' the Morph somewhere. If the Morph is dropped on a Morph that is willing to accept it (responds true to #wantsDroppedMorph:event:), the cursor removes the Morph from its structure and passes it along to the selected Morph. If the other Morph is unwilling to accept the grabbed Morph, the grabbed Morph is placed over the selected Morph in the World. Hmm, there's that World again, we'll have to talk about that soon.
Anyway, that's a HandMorph. It has some different behaviour than most of the Morphs because it does all the event dispatching, so the other Morphs know a little about it. In that sense, it's a special Morph. On the other hand, it pretty much falls under the concept of a Morph. It has a visual representation, and some behaviour. A working man's Morph. See, I told you. You don't believe me.
Also see: Why Morphic is Way Cool and The AlignmentMorph may be replaced by any Morph class