Activities/Turtle Art/Programmable Brick

Programmable Brick
The following feature—a block that can be programmed by the Pippy activity—is available in versions 44+ of Turtle Art.

Version 44 to 103
A copy of the tamyblock.py module is stored in the Journal when you first launch Turtle Art. All the sample modules are in this one file but all except one are commented out with #

You can edit the tamyblock.py module in Pippy. Then load the Python code into the Python block using the Pippy button on the Project toolbar. You can only have one type of Python block in your Turtle Art program.



Another way to load the Python block, is to click the Python code block found on the the Extras palette.

Version 104 onwards
There are two ways to create Python blocks: by loading sample code provided with Turtle Art or by loading Python code the your Journal.

loading sample code
A number of individual sample programs are provided. Clicking on the Load Python Block button on the Load/Save Toolbar will invoke a file-selector dialog. Select the sample that you want and it will be both copied to the Journal and loaded into a Python block.



loading code from the Journal
Clicking on a Python block that has been dragged onto the canvas from the Extras palette will invoke an object-selector dialog.



Select the Python code that that you want and that code will be loaded into the selected block.

You can't run a Python block by clicking on it, as that opens the object selector; instead attach the block to another one and click elsewhere on the stack you have created.

Which ever way you create them, multiple Python blocks can have different code loaded in them.

Sample code


def myblock(tw, line_length): ''' Draw a dotted line of length line_length. '''   try:  # make sure line_length is a number line_length = float(line_length) except ValueError: return if tw.canvas.pendown: dist = 0 while dist + tw.canvas.pensize < line_length: # repeat drawing dots tw.canvas.setpen(True) tw.canvas.forward(1) tw.canvas.setpen(False) tw.canvas.forward((tw.canvas.pensize * 2) - 1) dist += (tw.canvas.pensize * 2) # make sure we have moved exactly line_length tw.canvas.forward(line_length - dist) tw.canvas.setpen(True) else: tw.canvas.forward(line_length) return You can pass a list of up to three arguments to tamyblock.py as in the example below that converts the input to an rgb value.



def myblock(tw, rgb_array):  Set rgb color from values  tw.canvas.fgrgb = [(int(rgb_array[0]) % 256), (int(rgb_array[1]) % 256), (int(rgb_array[2]) % 256)]

def myblock(tw, x): ###########################################################################   #    # Push an uppercase version of a string onto the heap. # Use a 'pop' block to use the new string. #   ###########################################################################    if type(x) != str: X = str(x).upper else: X = x.upper tw.lc.heap.append(X) return

def myblock(tw, x): ###########################################################################   #    # Push hours, minutes, seconds onto the FILO. # Use three 'pop' blocks to retrieve these values. # Note: because we use a FILO (first in, last out heap), # the first value you will pop will be seconds. #   ###########################################################################    tw.lc.heap.append(localtime.tm_hour) tw.lc.heap.append(localtime.tm_min) tw.lc.heap.append(localtime.tm_sec) return

def myblock(tw, x): ###########################################################################   #    # Add a third dimension (gray) to the color model. #   ###########################################################################    val = 0.3 * tw.rgb[0] + 0.6 * tw.rgb[1] + 0.1 * tw.rgb[2] if x != 100: x = int(x)%100 r = int((val*(100-x) + tw.rgb[0]*x)/100) g = int((val*(100-x) + tw.rgb[1]*x)/100) b = int((val*(100-x) + tw.rgb[2]*x)/100) # reallocate current color rgb = "#%02x%02x%02x" % (r,g,b) tw.fgcolor = tw.canvas.cm.alloc_color(rgb) return

def myblock(tw, x): ###########################################################################   #    # Save an image named x to the Sugar Journal. #   ###########################################################################    tw.save_as_image(str(x)) return

def myblock(tw, x): ###########################################################################   #    # Push mouse event to stack #   ###########################################################################    if tw.mouse_flag == 1: # push y first so x will be popped first tw.lc.heap.append((tw.canvas.height / 2) - tw.mouse_y) tw.lc.heap.append(tw.mouse_x - (tw.canvas.width / 2)) tw.lc.heap.append(1) # mouse event tw.mouse_flag = 0 else: tw.lc.heap.append(0) # no mouse event

Device I/O
This Python block returns with the brightness sensor value in the heap. A range of parameters can be measured, for example, substitute any of the path strings in the table for the 'device' in the program below.

def myblock(tw, x): # ignores second argument import os   # The light sensor is only available on the XO 1.75 device = '/sys/devices/platform/olpc-ols.0/level' if os.path.exists(device): fh = open(device) string = fh.read fh.close tw.lc.heap.append(float(string)) # append as float value to heap else: tw.lc.heap.append(-1)

Look in /sys/devices on your computer to find other devices you may be able to access.

You can also read events in /dev/input. Use the od (octal dump) command to inspect these events, eg sudo od /dev/input/event0

You can access the following events on the X0-1.75, (some on X0-1.0 -1.5)
 * accelerometer: /dev/input/event0 ???
 * power button: /dev/input/event1
 * lid switch: /dev/input/event2
 * ebook: /dev/input/event3 (XO-1.75) event4 (XO-1.0 - 1.5)
 * headphone jack: /dev/input/event7
 * microphone jack: /dev/input/event8
 * rotate, cursor, and game pad keys: /dev/input/event10 (XO-1.75) event6 (XO-1.0 - 1.5)
 * mouse : /dev/input/mice

For example, the code below waits till the ebook switch state changes and pushes the status to the heap

def myblock(tw, x): # ignores second argument import os  devicestr='/dev/input/event3'              #the ebook switch cmd='sudo chmod 777 {!s}'.format(devicestr) os.system(cmd)                            #caution! changing system file permissions fd = open(devicestr, 'rb') for x in range(12): fd.read(1)                             #does not return till the switch state changes tw.lc.heap.append( ord(fd.read(1)))       #push ebook switch state to heap fd.close

Understanding the structure of the Turtle Art program
Turtle Art offers two blocks for adding Python code,
 * the Python function block [[image:Pythonfunctionblock.jpg]] adds a single line of code,
 * the Python code block [[image:Pythoncodeblock.jpg]] supports multi-line code.

Python function block
The Python function block is processed through tajail.py. For security reasons, it cannot access Turtle Art objects. It can it only access the Python language and the time and math libraries as the following extract from tajail.py shows.

from time import * from math import *

For more information on allowable syntax for this block:
 * Python language, see http://docs.python.org/tutorial/
 * math library, see http://docs.python.org/library/math.html
 * time library, see http://docs.python.org/library/time.html
 * Numpy library, see numpy.scipy.org/ (Not supported as of v104)

Python code block
Turtle Art is created in object oriented Python code. This is based around the definition of classes and the creation of object(s) which are instance(s) of that class. These objects then have properties and methods which are defined by their class.

See http://docs.python.org/tutorial/classes.html for a description of classes in Python.

See the file TurtleArtActivity.py. This is where it starts. When an instance of TurtleArtActivity is created, setup_canvas creates an instance of TurtleArtWindow: self.tw This instance of TurtleArtWindow creates an instance of LogoCode: self.tw.lc and an instance of TurtleGraphics: self.tw.canvas

tamyblock.py gets passed a LogoCode instance, lc, and everything is relative to that instance. tw is passed to lc and set as an instance data object at init. This allows referral back to tw when needed. Consequently, Class TurtleArtWindow is accessed through lc.tw. and Class TurtleGraphics is accessed through lc.tw.canvas

Class TurtleArtWindow – useful properties and methods (from within tamyblock.py, lc.tw is the class instance)

Class TurtleGraphics – useful properties and methods (from within tamyblock.py, lc.tw.canvas is the class instance)

Other useful Python functions