links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Fun with Morphic
Last updated at 7:27 am UTC on 2 November 2018
Note: This tutorial does not work well. Not enough details. It contains some hints what you could do.

"Fun with Morphic 2006"
By John Maloney
{JMM from my notes, expect roughness until Maloney cleans it up}

Create a new category
Created a new subclass from Morph called TestMorph
 Morph subclass: #TestMorph
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'Morphic-Demo'
Start from nothing

 TestMorph new openInWorld 

in Morphic

This makes a little blue rectangle on the screen, we are 90% there.
{Well of course content is missing, but?}

The TestMorph has default methods to be a complete Morph so you can start with a working object and debug it into existence. Why write code in a browser when you can debug/create live objects?

First change the appearance
 drawOn: aCanvas

This is passed a canvas that you draw upon.

Morphic-Support Canvas has lots of drawing methods. So for example
We used


for the #drawOn: method

drawOn: aCanvas

 aCanvas fillOval: self bounds color: Color red

Of course we can resize the Morph, which changes it's boundaries. The Morph has bounds, and protocol that is used to define it's actions.
Conceptually it iss small, but lots of methods due to class code creep.

Back to the "Fun with Morphic" cheat sheet. Which Maloney used to drop code fragments from, why type when you can cut and paste.

handleMouseDown: anEvent

Now we tell the environment that we care about mouse events. This means changing the handler handlesMouseDown: anEvent

The default action is to return

 handlesMouseDown: anEvent

What is an event?

This is an MorphicEvent, Morphic is completely event driven, the VM isn't but you don't care at the Morphic layer.

So in our example we see the type of event, the cursor, which keys were pressed, which button.


Oh and a sourceHand a HandMorph which means you can tie an event to a User. So for example in multi-worlds you can make decisions about actions based on the user. {Remember Morphic can support many users in the same world}

mouseDown: anEvent

 mouseDown: evt 

We did
 self position: self position + 10

position: handles damage control etc.

Little for us to do.
If you look at
 position: aPoint
You see a postion recalculation and some more code to handle the screen update.

 self changed
 self privateMoveBy :delta.
 self changed

This is need to invoke the change. Changed doesn't perform the same action as in VW. Dan Ingalls pointed out we don't worry about screen updates/damage control it happens in the lower level.

One of the key things was double buffering to prevent flashing etc and make movement of objects very very smooth. Morphic tracks all the damage and has step methods. So movement and animation is smooth that was the original goal for the framework.

In PasteUpMorph>>displayWorld we have a ifTrue were we can have morphic display the damaged area before the update.

(Fun with Morphic has more on this, including changes for 2.9). {HEY this should be a global option we can turn off or on, versus seeking out commented code in the image}

A Question about lots of Morphs in a world was asked. If I've a few say a thousand or so then things slow down? Yes true in the past, but things are better now, but not a free lunch, more Morphs then the slower the action.

A delay in Morphic gives back CPU cycles if nothing is going on, also controls the amount of time stepping is done. JMM talked later about this, you can find more at
{ http://www.smalltalkconsulting.com/papers/tipsAndThoughts/codeFragments.html}

Ok now what if want to move the object draw along a path.
Add a instance variable, and it's create and initialization methods.

We then reflected on some features of Squeak for a few minutes:
The Exchange command which was used to manipulate objects in the category reorganization panel

Select object 1, then object 2 then "command e" it changes the objects in the category reorganizer.

Added step method, then startAnimation which creates 10 positions relative to current position.

Grab Morphic, then get inspect Morphic and do the startAnimation
method. In this example we moved down then up.

Ok it's slow, so lets see stepTime. The default is 1000 milliseconds, which might not be viable for what you want to do. So we changed it to 10 and on a fast machine it worked just fine.

Ok now lets change mouseDown; evt and invoke self startAnimation.

Now we changed the startAnimation to mimic gravity. Note the thing will bounce even when showing the halos.

Another example, PicoPaint a simple graphics editor. Maloney built a simple canvas editor tool using just a few statements. This shows the power of Morphic to get complicated things done in a hurry.

We need to modify

 drawOn: aCanvas image: form at: bounds origin.


which is more complicated

Morphic has a relative position to the upper left corner, but we need to transform globals to local coordinate system. In this method we need to mange the redraw based on the current and previous mouse position.

	Creates a pen on the form.

	Supports resizing the old canvas.

So we now have a painting program in a few methods of only a few lines.

Question about pen pixel size. This could easily be done in a few hours perhaps some Squeaker could do this on Sunday.

Ok, now the tool is slow we can outrun the painter?
In this case drawing really fast resulting in straight lines. The problem is most of the canvas gets updated on the redraw and that takes too much time.

To the change tool. A new feature to show a method, with new code in a color, and stuff removed struck out. John used this to restore some more complicated code to track bounding boxes.

Now the class can track the pen much better since the update rectangle is much smaller than the original solution.

Custom menus

Ok another feature. Add a menu.
 addCustomMenuItems: aCustomMenu hande: aHandle
This allows you to add menu items to the existing menu.
So now we can invoke a method. So lets add brushColor

In setPenColor: evt
Invokes evt hand changeColorTarget:selector:

Which brings up the color palette and allow us to change the color of the pen on the fly.

Create a new pen size menu. Which allows us to pick a size, we then create a new pen

Added a fill command.
The Form shapeFill: interior point
Command allows us to fill a selected object.

The good things, if you know what to override you have freedom. The framework manages all the other stuff you don't need to add any code to get a Morphic to work/behave/interact.

Alas it's hard to understand, some cleanup is needed.

Global versus Local
A Transformation Morph used translate coordinates to allow rotation etc. This intermediate object makes things harder to understand. This area will be reworked to fix things.