How To Etoys: Implementing new Functionalities - hpi-swa-teaching/Etoys-Calliope GitHub Wiki
Player - Morph
To implement a new Etoys Morph you need two basic classes: the player and the morph. The player implements functionality while the morph is responsible for appearance (‘costume’ of the player).
Important methods for the morph:
On the class side:
descriptionForPartsBin
"Answer a description for use in a parts bin."
^ self partName: 'Calliope Mini' translatedNoop
categories: {'Calliope' translatedNoop}
documentation: 'A Mini Computer' translatedNoop
sampleImageForm: (Form fromFileNamed: 'mini_board.png').
Implement this method to give the Object Catalog some information about your Etoys Morph. The second line also inititalizes the new category. The last line is optional.
On the instance side:
initializeToStandAlone
this method is called when you drag the morph out of the object-browser. You can use it to initialize your morph.
self assuredPlayer
You should call this when your morph is dragged out to make sure it has a Player attached.
newPlayerInstance
"This method should return an instance of your player"
^YourPlayerClass newUserInstance.
Viewer
allAdditionsToViewerCategories
This method determines which categories will be shown in the viewer.
In its implemented state in the regular Image, it will choose all methods that have a prefix of “additionsToViewerCategory” and create categories for the suffixes (see below).
We had to modify this method directly instead of overriding it to only show our Calliope categories: We changed the selector to “additionsToViewerCategoryCalliope” and set the counter to 34 instead of 26. This is not necessary for the things to work, but it makes using Etoys for Calliope a little easier.
additionsToViewerCategory
this method will add new categories to the viewer. E.g. Grundlagen, Eingabe, etc.
It is implemented on the class side of your morph.
You suffix the method name with the type of methods the category should hold. For the category “test” the name would be additionsToViewerCategoryTest.
We have implemented a workaround to the method allAdditionsToViewerCategories (see below), which will only load our Calliope categories into the viewer, which is why our categories always also carry the suffix Calliope. For each new category you implement a new method on the class side of your morph.
First, you declare the name of the category. Usually it will be the same as the suffix of the method. In the viewer, categories will be ordered alphabetically by this name.
Next, you may add slots or commands to your category.
In cursive are indices that you choose to set, in bold are methods you need to implement.
A slot is used for states of the morph. In our case, the RGB Led has a slot which holds its color.
A new slot is an array which looks like this:
#(slot nameOfSlot ‘descriptionOfSlot’ type readWrite/readOnly #Player getterForVariable #Player setterForVariable:)
This will create a slot of the given type in your viewer. Via its getter it will show the current value of the variable. Whenever the user changes the value in the script, the setter will be called. Getters and setters need to be implemented on the instance side of your player.
A command calls a method on a given variable.
A command is also an array and can look like this:
#(command methodToBeCalled: ‘descriptionOfCommand’ type)
This will create a code block which on execution will call the method you choose. The parameter for this method will be whatever the given type holds.
I.e. if the method is showNumber: and the type is Number (this is set to 5 by default), on execution of the code block will call showNumber: 5.
A command can also execute methods without parameters, like so:
#(command methodToBeCalled ‘descriptionOfCommand’)
A good example of this is “clearScreen”, which on execution only does one thing: clear the screen.
Implementing your own types and tiles
Sometimes the default types Squeak offers are not enough. For Calliope it was for example necessary to implement a type “CalliopeIcon”, since this would be a parameter for the methods we use to manipulate the LED Matrix.
If you identify the need to add your own type and tile, you will firstly have to add two classes: CalliopeYourType and CalliopeYourTile. Substitute “Your” for whatever the type may be.
CalliopeYourType
This class only needs two methods. On instance side, implement defaultArgumentTile with your designated tile. On class side, override initialize and add your type to the default vocabulary with: Vocabulary allStandardVocabularies at: #CalliopeYour put: self new.
Whatever you pick here will be the type you put in your command or slot!
This will make sure, you have your default tile set and ready in place.
CalliopeYourTile
Depending on what your tile should do, you will have to implement different methods here. Refer to the already implemented tiles for inspiration and input.
Methods you may find useful:
parseNodeWith:
This is called whenever the code block is recompiled, which happens whenever something in it is changed.
value
This is the “transformation” method used whenever you have a tile that must be somehow modified to give you a string that is useful smalltalk-code. Refer to you LedPickerTile for an example.
They work together like so: parseNodeWith needs to know how to modify the so-called literal - the piece of code that will be put into the program that is compiled from the codeblock. Value gives the method that does the actual transformation and should always return a string.
Events
When you want a script to be run on a custom event you do the following.
Sometime during your initialization you should register the events in your scripting system as follows:
ScriptingSystem
addCustomEventFor: self
named: #ButtonAClicked
help: 'when button A is clicked '
targetMorphClass: CalliopeMorph. `
Then in your handlesMouseDown: you can trigger them in the following way:
handlesMouseDown: anEvent
(self buttonA containsPoint: (anEvent position)) ifTrue: [ self triggerEvent: #ButtonAClicked].
^ true
So when you assign a script to be run when the event ButtonAClicked is triggered, it will do exactly that.