Activity Team/Modifing an Activity

From Sugar Labs
< Activity Team
Revision as of 15:40, 30 August 2009 by Dfarning (talk | contribs) (import contents)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search


This describes how to reprogram activities using Sugar and the activities Browse, Pippy & Terminal. It does not require any extra development tools. Development is done directly on the OLPC XO, alternatively it can be done using the Live CD, Sugar on a Stick or other implementations of Sugar.

This page is targeted at beginners, more experienced users may find reading Activities/Turtle Art/Patching , Activity_Team/Resources and Activity_Team/Creating_a_New_Activity useful.

The activities are stored at /home/olpc/Activities and you can use the browser as a "file manager" to browse the file system using the URL prefix file://

For example, type file:///home/olpc/Activities/TurtleArt.activity into the browser address bar to see the Python files that make up the TurtleArt activity. Click on one of the *.py files to inspect the code.

You can view the code but not edit it in the browser. To edit, select the code and copy to the clipboard (ctrl c) and open Pippy (the Python editor) and paste it to the code window (ctrl v). You can then edit the code and save it to the Journal, keep as Pippy document and using a suitable filename (eg

To run the modified code, you need to copy it from the journal back to the directory that the activity resides in, in this case /home/olpc/Activities/TurtleArt.activity

Start the terminal activity and navigate to the activity's directory. It is a good idea to use mv (move) to backup the original file to filename.bak before it gets overwritten. Then copy the edited file from the journal.

    cd /home/olpc/Activities/TurtleArt.activity
mv filename.bak

(Though there may be a message that it is copying the latest of a large number of objects of that name, mostly that's OK, but occasionally I find that I have saved an empty file. I think copy-from-journal copies the most recent item in the journal, so access these items immediately before you copy them)
Due to a bug(?), it may save as
If you need to rename the file use the move command


There is an activity Develop which has a file manager and an editor, currently (at writing this) version 35 seems to be buggy. It shares the limitation with the above method that it saves to the journal, not the activity's directory. If working OK, its only benefit may be avoiding the step of copying from Browse to Pippy

Modifying TurtleArt Files

Turtle Art has a special block that is programmable in Pippy. Look for the entry in your Journal. Try uncommenting one of the examples.

Use the Pippy import button to import your code into Turtle Art.


Your code is associated with the myblock.svg block found on the Sensors palette.


Examples: File Viewer Orbital Motion Oscilloscope

The file does a lot of the calculating. For example, careful divide avoids overflow errors by returning 0 for division by zero.

def careful_divide(x,y):
if y==0: return 0
return x/y

Modify it to return 42 for division by zero

def careful_divide(x,y):
if y==0: return 42
return x/y

Bad divide.jpg

Swap the functions of pen up and pen down by substituting True and False

defprim(lc,'pendown', 0, lambda lc: setpen(, True))
defprim(lc,'penup', 0, lambda lc: setpen(, False))


defprim(lc,'pendown', 0, lambda lc: setpen(, False))
defprim(lc,'penup', 0, lambda lc: setpen(, True))

Bad pen.jpg

This file is not used by Sugar to launch TurtleArt but you can use it to launch TurtleArt from the terminal, go to /home/olpc/Activities/TurtleArt.activity and type


it will open without the menu bar, it is also in Spanish because it is hard coded.

twNew(win1, os.path.abspath('.'),'es')

change es to en in the file and it will launch in English

twNew(win1, os.path.abspath('.'),'en')

This file handles the turtle drawing functions, for example the following code calculates which of the 36 turtle sprites, each rotated by 10 degrees to draw, depending on the heading.

def turn_turtle(t):
   setshape(t.spr, t.shapelist[(int(t.heading+5)%360)/10])

A correction of 5 degrees is added so that the turtle is facing straight up for headings -4.999 to +4.999 degrees.
Good heading.jpg
Change +5 to +0 and the turtle is rotated left for any heading<0

def turn_turtle(t):
   setshape(t.spr, t.shapelist[(int(t.heading+0)%360)/10])

Bad heading.jpg

This file controls, amongst other things the docking behaviour of the blocks. The arithmetic operators +-*/ have equal block dimensions and dock both sides with number blocks. They are defined as having an ari docking style.


And the docking points, left and right, are given coordinates in the following code

 'ari':     (('numend',True,12,20),('num',False,39,20)),

The effect of changing the y coordinates of the left and right docking points from 20 to 10 and 30 are shown below.

 'ari':     (('numend',True,12,10),('num',False,39,30)),

Bad ari dock.jpg

Modifying Speak

Editing a language dictionary

This is based on information at Instructions for implementing a new language "voice" for Speak on the XO.

In the following, Speak is modified so that it spells out the letters in 'OLPC' rather than trying to pronounce it as a word, only the English pronunciation dictionary is modified.

There is a dictionary for each language (eg. en_dict for English) which is compiled from a rules file and a list file, you can find a description of the syntax for these files in the dictionary documentation. In this example, the rules and list files are downloaded as a zip (compressed) file, the en_list file is edited and a new dictionary en_dict is created from the files en_rules and en_list

Download the source files for espeak from

Go to the Journal where you will find File

Open this with Etoys, extract all to the suggested directory /home/olpc/isolation/1/uid_to_home_dir/1004/data/MyEtoys 1004 (or similar) seems to be a temporary directory and may be different in your case, keep Etoys open till you have copied the required files

In the suggestion is to use the Linux vi text editor, here Write is used as the text editor.

Open Terminal and go to directory /home/olpc/isolation/1/uid_to_home_dir/1004/data/MyEtoys/espeak-1.40.02-source/dictsource (or similar)

    cd /home/olpc/isolation/1/uid_to_home_dir/1004/data/MyEtoys/espeak-1.40.02-source/dictsource

copy-to-journal the list and rules files for the English dictionary, the Mime 1 2 3 type is text/plain

    copy-to-journal en_list -m text/plain
    copy-to-journal en_rules -m text/plain

Go to the Journal and open the en_list file with Write and edit to indicate that the string 'OLPC' is to be spoken as an abbreviation:

    ok	        $abbrev
    olpc	$abbrev
    omg	$abbrev

keep as text

Go to Terminal and copy both files from the Journal

(these files are copied to a temporary directory /home/olpc rather than the final destination /usr/share/espeak-data because either copy-from-journal does not have the required permission or I do not know the syntax for user root)

    cd /home/olpc
    copy-from-journal en_list
    copy-from-journal en_rules

I think copy-from-journal copies the most recent item in the journal, so access both these items immediately before you copy them, keep them as text. The files are copied across as en_rules.txt and en_list.txt to directory cd /home/olpc You can use Browse to check the contents of both files, just put /home/olpc in the address bar

Finally, go to the destination directory, /usr/share/espeak-data , change the user to root, back up the old dictionary, copy the list and rules files from /home/olpc while removing the txt extension, compile them to create a new en_dict and exit root user shell

    cd /usr/share/espeak-data
    mv en_dict en_dict.bak
    mv /home/olpc/en_rules.txt en_rules
    mv /home/olpc/en_list.txt en_list
    espeak --compile=en

Start Speak and type OLPC

Files are at /home/olpc/Activities/Speak.activity
Modify the initial greeting on startup by editing Hello %s. Type something
%s is a placeholder for your name

self.say(_("Hello %s.  Type something.") % xoOwner.props.nick)

Modifying Ruler the menu system the initial screen of 3 rulers the cm and mm grids the checker board the 90deg and 360 deg protractors 4 utility functions including pixel (dots per inch) to mm conversion

The conversion to mm is by

def mm(n):
   return n / 25.40 * 200

change to inches and tenths with

def mm(n):
   return n / 10.00 * 200

change labels from cm & mm to inches and tenths
get the protractors correctly centred on the screen

Shown below is the code relating to drawing the quadrant protractor, comments are added.
Show angle.jpg

class Angles90(paper.Drawing):
   def draw(self,c):
ox = mm(0) #x origin at LHS oy = mm(99) #y origin at bottom d = mm(90) #default line length 90mm def xy(angle,m=d): #calculate line x,y from angle return cos(-angle)*m+ox,sin(-angle)*m+oy def ray(angle,r0=0,r1=d): #default lines from origin c.move_to(*xy(angle,r0)) #start point c.line_to(*xy(angle,r1)) #end point
lw = 6 #line width 6 pixels c.set_line_width(lw) c.move_to(ox,oy+lw/2) c.line_to(*xy(pi/2)) #vertical line ray(0) #horizontal line c.stroke() c.set_line_width(3) c.set_dash([mm(5)]) ray(pi/4) #dashed line 45 degrees c.stroke() c.restore()
c.set_line_width(4) #line width 4 pixels for a in range(10,81,10): #every 10 deg from 10 to 81 ray(d2r(a),mm(10),mm(85)) #radius 10 to 85mm c.stroke() #10 degree lines, thick outer section c.set_line_width(2) #width 2 pixels for a in range(10,81,10): #every 10 deg from 10 to 81 ray(d2r(a),mm(3),mm(20)) c.stroke() #10 degree lines, thin inner section (overwritten by 5 deg lines)
c.set_line_width(2) #width 2 pixels for a in range(1,90,1): #every 1 deg from 1 to 90 ray(d2r(a),mm(70),mm(80)) #1 deg lines from 70 to 80 radius c.stroke() #1 degree lines c.set_line_width(2) #width 2 pixels for a in range(0,90,5): #every 5 deg from 0 to 90 ray(d2r(a),mm(20),mm(81)) #radius 20 to 81mm c.stroke() #5 degree lines

The purpose of the numeric coefficients should be apparent. Try altering them and predicting the result.
Try adding numbers to the 10 degree lines.
Display the mouse coordinates in mm.

Modifying Calculate

Two mods to increase the discoverability of the help and plot functions. Two new buttons are added. A help (?) button puts the string 'help' into the display, pressing enter then displays help. A plot (plt) button puts the plot template in the display. Enter values and press enter.
Modified keypad.jpg
Reduce the width of the clear button

 [3, 0, 3, _('Clear'), self.col_gray1, lambda w: self._parent.clear()],


 [4, 0, 2, _('Clear'), self.col_gray1, lambda w: self._parent.clear()],

and add two buttons, one for help and the other for plot

 [2, 3, 1, '?', self.col_gray2, lambda w: self._parent.add_text('help')],
[3, 0, 1, 'plt', self.col_gray3, lambda w: self._parent.add_text('plot(eqn,var=-a..b)')],

Modifying TamTam

Add new instrument

Obtain two images for new instrument (see examples)

  • dimensions 112x112
  • alpha channel should present
  • one copy for normal-state
    • name is "<name_of_instrument>.png"
    • image of instrument is "shadowed"
  • one copy for selected-state
    • name is "<name_of_instrument>sel.png"
    • image of instrument is not "shadowed"
    • image is framed

Place all files to common/Resources/Images directory

Obtain sound file for new instrument with follow preferable characteristics

  • filename is "<name_of_instrument>" (w/o suffix)
  • Uncompressed PCM, 16KHz
  • ...

Place file to common/Resources/Sounds directory

Change common/Util/ file by adding new line

_addInstrument("<name_of_instrument>", <type>, <register>, '<category>', <start>, <end>, <duration>, <scale>)
  • type type of sound processing
    • INST_SIMP "simple" playing (try it first)
    • INST_TIED some kind of processing filters
  • register ...
    • LOW ...
    • MID ...
    • HIGH ...
    • PUNCH ...
  • category group of instruments
    • animals
    • percussions
    • strings
    • winds
    • percussions
    • keyboard
    • concret
    • people

Add new drum kit

Prepare three images, two like for regular instrument and follows one

  • name is "<name_of_instrument>selgen.png"
  • image is (another) framed see

Place all files to common/Resources/Images directory

Create sound files

and place them all to common/Resources/Sounds directory

Add follows line to common/Util/ for every of 13 stages

_addInstrument("<unique_name_of_drum_stage>", <type>, <register>, '<category>', <start>, <end>, <duration>, <scale>, kitStage=True)

and lines for drum itself

<any_unique_varname> = { 24 : "<name_of_drum_stage_1>",
                         26 : ...,
                         28 : ...,
                         30 : ...,
                         32 : ...,
                         34 : ...,
                         36 : ...,
                         38 : ...,
                         40 : ...,
                         42 : ...,
                         44 : ...,
                         46 : ...,
                         48 : "<name_of_drum_stage_13>" }
_addInstrument("<name_of_drum>", 0, 0, "percussions", 0, 0, 0, 1, <any_unique_varname>)

To use new drum kits in TamTamMini #285 bug should be fixed.

Modifying Chat

Using Pippy

Modifying the Chat activity can be done with Pippy! (since #5542)

Open up the Chat activity and hit fn + spacebar (view source key). The source for the Chat activity will be shown in the Journal. Click Start to open the source with Pippy.

Make your modifications to Chat and Keep --> As Activity Bundle. Your new activity will pop up as "Chat Source Bundle" in the Journal. Click start to try out your modifications.

Text Display

Changing how text is displayed in text is done in the function:

def add_text(self, buddy, text, status_message=False):

The source contains a description and diagram of how to modify how text is displayed on the screen.

        Display text on screen, with name and colors.

        buddy -- buddy object or dict {nick: string, color: string}
                 (The dict is for loading the chat log from the journal,
                 when we don't have the buddy object any more.)
        text -- string, what the buddy said
        status_message -- boolean
            False: show what buddy said
            True: show what buddy did

        hippo layout:
        .------------- rb ---------------.
        | +name_vbox+ +----msg_vbox----+ |
        | |         | |                | |
        | | nick:   | | +--msg_hbox--+ | |
        | |         | | | text       | | |
        | +---------+ | +------------+ | |
        |             |                | |
        |             | +--msg_hbox--+ | |
        |             | | text | url | | |
        |             | +------------+ | |
        |             +----------------+ |

Modifying SocialCalc

SocialCalc is a spreadsheet activity. You can find information on how it is programmed at PROGRAMMING OF SOCIALCALC.

It is primarily written in Java with some Python code to "Sugarise" it. You will find the Python code at //home/olpc/Activities/SocialCalcActivity and the Java code in the web subdirectory.


In the web subdirectory the file socialcalcconstants.js contains a number of constants including the error message strings and date format.

For example at line 341, the string s_calcerrunknownname: "Unknown name" is the error message for when you type an unrecognised string into a cell. Try typing =abc into a spreadsheet cell and it displays as Unknown name "ABC"

You can use Pippy as your editor, even though the file being edited is Java script. Just follow the instructions at the beginning of this article but substitute .js for .py

Editing line 341 to read s_calcerrunknownname: "Unknown namey thing" results in an error message for =abc of Unknown namey thing "ABC"

The month names for date formatting cells are at line 310 s_FormatNumber_monthnames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], Edit this to change month names in cells which are date formatted.

The help for the functions are at lines 352-462. For example, edit the string s_fdef_ACOS: 'Trigonometric arccosine function. ', to change the text shown in this image. Calcfunc.jpg

Help for the arguments that the functions require are at lines 464-499. For example, the string s_farg_v: "value", results in the image below.


The text for the function categories is at lines 503-512

  s_fclass_all: "All",
  s_fclass_stat: "Statistics",
  s_fclass_lookup: "Lookup",
  s_fclass_datetime: "Date & Time",
  s_fclass_financial: "Financial",
  s_fclass_test: "Test",
  s_fclass_math: "Math",
  s_fclass_text: "Text",


There are lots more constants that you can experiment with.


formula1.js parses formulae entered into cells. It also has the code for functions.

Modifying Physics

Changing block properties - density

Physics is based on Box2D v2.0.2 , there is good documentation. It is 'wrapped' in a python wrapper called elements which is then 'Sugarised' to make Physics. It was originally on the OLPC wiki but has now migrated to the Sugarlabs wiki.

You will find the 'Sugarising' code at /home/olpc/Activities/Physics.activity directory and the Elements code in the elements subdirectory and the Box2D code in a further box2d subdirectory.

Here is an example, you can make rectangles have a lower density than other shapes.

Edit the file in the /home/olpc/Activities/Physics.activity directory.

In the box creation tool

    # The box creation tool        
    class BoxTool(Tool): 

edit line 103 to read, self.rect.width/2, self.rect.height/2, dynamic=True, 
    density=0.01, restitution=0.16, friction=0.5)

Alternatively you could get the same result editing the file in the /home/olpc/Activities/Physics.activity/elements directory. Force the function

    def rect(...) 

to have density of 0.01. at line 147 add the following code

    density = 0.01


Equal density (1.0)


Modified so rectangles have a density of 0.01

Adding a keyboard shortcut

A more sophisticated approach would be to use keyboard shortcuts

  • l = light, density=0.1
  • n = normal, density=1.0
  • h = heavy, density=10

Edit the file in the /home/olpc/Activities/Physics.activity directory.

Add the following code in the event handler, handleEvents(self,event), of class Tool(object)

           elif event.key == K_h:
           elif event.key == K_l:
           elif event.key == K_n:

add the following code in the __init__ method of class BoxTool(Tool)

           self.setdensity =1

finally modify this line of code to set density to self.setdensity rather than 1.0, self.rect.width/2, self.rect.height/2, 
        dynamic=True, density=self.setdensity, restitution=0.16, friction=0.5)

Do the same for circles, triangles and polygons.


The class BoxTool is a derived class of the base class Tool. Attributes in a derived class override attributes in a base class, if the attribute is not defined in the derived class, then the base class attribute is inherited. When an instance of BoxTool is created, the __init__ method of class BoxTool runs, the __init__ method of class Tool is overridden. But handleEvents(self,event) is inherited from class Tool because it is not defined in class BoxTool. The default density is set in __init__ , it is altered by handleEvents and is used to create a rectangle of the appropriate density in

The significance of 'self' is that it is the current instance of BoxTool. Using self.density means the variable density in the current instance. For more on classes see Python Tutorial, Section 9, Classes or Gasp Lessons.

Adding toolbar buttons

The *.svg icons were created for the 3 densities, using the vector drawing package Inkscape. A feather, wood and rock:

They can be downloaded to the journal, they save as File index.php from... Do not open them or the paint activity will corrupt them. They need, each in turn, to be the top (most recently accessed) items in the journal for copy-from-journal to work.

In terminal change to directory /home/olpc/Activities/Physics.activity/icons

 copy-from-journal feather.svg
 mv feather..svg feather.svg

and same again for wood and rock.

Edit the file in the directory /home/olpc/Activities/Physics.activity add the following code in build_toolbar(), just after the code for self.destroy that places three new toolbuttons to the right of the existing buttons.

       self.light = RadioToolButton(, named_icon='feather')
#        self.light.connect('clicked',self._light_cb)
       self.normal = RadioToolButton(, named_icon='wood')
#        self.normal.connect('clicked',self._normal_cb)
       self.heavy = RadioToolButton(, named_icon='rock')
#        self.heavy.connect('clicked',self._heavy_cb)


Modifying ConozcoUruguay Activity (in Spanish)

See for how to modify the contents of the ConozcoUruguay Activity to develop content, create new questions and new levels of play. This description is particularly directed to those who have no programming skills. (in Spanish but see for a translation)


the One Laptop per Child laptop hardware
the underlying computer operating system. If you start the Terminal activity you are looking at a Linux command line interface.
the GUI (Graphical User Interface) for the operating system. It is written in Python and launched from Linux. It is what you see when you turn on your XO or launch Sugar on a Stick.
the programming language that most activities are written in. Source files have a *.py extension. It is an interpreted language, not a compiled one; programs run when the Python interpreter reads and interprets the *.py files; there are no executable (*.exe) files. The Pippy activity is a Python editor.
If you read a *.py python source file, you are not seeing the whole story. Libraries of code are imported, often at the start of a *.py file you will see libraries imported, e.g.,
import pango
import gtk

Some of the more commonly used libraries:

GTK - a library for creating graphical user interfaces.
pango - text rendering library
cairo - graphics rendering library
pangocairo - the library integrating Pango and cairo
math - gives access to library functions for floating point math
time - this module provides various time-related functions.
sugar - the sugar Package allows access to several modules and subpackages
gobject - an abstraction layer that allows programming with an object paradigm
os - this module provides a unified interface to a number of operating system functions.