Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pysamples
diff options
context:
space:
mode:
Diffstat (limited to 'pysamples')
-rw-r--r--pysamples/COPYING21
-rw-r--r--pysamples/copy_from_heap.py37
-rw-r--r--pysamples/dotted_line.py136
-rw-r--r--pysamples/grecord.py227
-rw-r--r--pysamples/load_block.py78
-rw-r--r--pysamples/load_journal_entry_to_heap.py39
-rw-r--r--pysamples/paste_to_heap.py36
-rw-r--r--pysamples/push_mouse_event.py50
-rw-r--r--pysamples/push_time.py40
-rw-r--r--pysamples/save_heap_to_journal_entry.py44
-rw-r--r--pysamples/set_rgb.py61
-rw-r--r--pysamples/sinewave.py36
-rw-r--r--pysamples/speak.py57
-rw-r--r--pysamples/svg_end_group.py17
-rw-r--r--pysamples/svg_start_group.py17
-rw-r--r--pysamples/uturn.py35
16 files changed, 608 insertions, 323 deletions
diff --git a/pysamples/COPYING b/pysamples/COPYING
new file mode 100644
index 0000000..9cdf1e6
--- /dev/null
+++ b/pysamples/COPYING
@@ -0,0 +1,21 @@
+Copyright (c) 2008-11, Walter Bender
+Copyright (c) 2008-11, TOny Forster
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/pysamples/copy_from_heap.py b/pysamples/copy_from_heap.py
index 8483fde..fbca999 100644
--- a/pysamples/copy_from_heap.py
+++ b/pysamples/copy_from_heap.py
@@ -1,35 +1,16 @@
-#Copyright (c) 2010, Walter Bender, Tony Forster
+#Copyright (c) 2010-11, Walter Bender, Tony Forster
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the FILO heap will be copied to the clipboard.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
-
-def myblock(lc, x):
-
- ###########################################################################
- #
- # Copy heap to clipboard
- #
- ###########################################################################
+def myblock(tw, x): # second argument is ignored
+ ''' Copy heap to clipboard '''
from gtk import Clipboard
- from tautils import data_to_string
+ from TurtleArt.tautils import data_to_string
- Clipboard().set_text(data_to_string(lc.heap))
+ Clipboard().set_text(data_to_string(tw.lc.heap))
diff --git a/pysamples/dotted_line.py b/pysamples/dotted_line.py
index 9db7f9d..febd409 100644
--- a/pysamples/dotted_line.py
+++ b/pysamples/dotted_line.py
@@ -1,42 +1,23 @@
-#Copyright (c) 2009-10, Walter Bender
+#Copyright (c) 2009-11, Walter Bender
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
-
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
-
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-
-#
# This procedure is invoked when the user-definable block on the "extras"
# palette is selected. Some examples of how to use this block are included
# below. Try uncommenting an example or write your own Python code.
-#
+#
# To uncomment code, remove the '# ' in the Python code. Take care to preserve
# the proper indentations.
#
-#
+#
# NOTES:
-#
+#
# 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.
-#
+#
# Class Defined in Instance Created in
# TurtleArtWindow tawindow.py tw TurtleArtActivity.py
# LogoCode talogo.py lc tawindow.py
@@ -44,72 +25,72 @@
# Turtles, Turtle taturtle.py turtles tawindow.py,
# tacanvas.py
# Blocks, Block tablock.py block_list tawindow.py
-#
-#
+#
+#
# Class TurtleArtWindow -- useful properties and methods (from within
-# tamyblock.py, lc.tw is the class instance)
-#
+# tamyblock.py, tw is the class instance)
+#
# Methods and data attributes Example
-# set_fullscreen(self) lc.tw.set_fullscreen()
+# set_fullscreen(self) tw.set_fullscreen()
# Note: Hides the Sugar toolbar
-# set_cartesian(self, flag) lc.tw.set_cartesian(True)
+# set_cartesian(self, flag) tw.set_cartesian(True)
# Note: True will make the overlay visible;
# False will make it invisible
-# set_polar(self, flag) lc.tw.set_polar(True)
+# set_polar(self, flag) tw.set_polar(True)
# Note: True will make the overlay visible;
# False will make it invisible
-# hideshow_button(self, flag) lc.tw.hideshow_button()
+# hideshow_button(self, flag) tw.hideshow_button()
# Note: Toggles visibility of blocks and palettes
-# self.active_turtle lc.tw.active_turtle
+# self.active_turtle tw.active_turtle
# Note: The active turtle instance
-#
-#
+#
+#
# Class TurtleGraphics -- useful properties and methods (from within
-# tamyblock.py, lc.tw.canvas is the class instance)
-#
+# tamyblock.py, tw.canvas is the class instance)
+#
# Methods and data attributes Example
-# clearscreen(self) lc.tw.canvas.clearscreen()
+# clearscreen(self) tw.canvas.clearscreen()
# Note: Clears the screen and resets all turtle and
# pen attributes to default values
-# setpen(self, flag) lc.tw.canvas.setpen(True)
+# setpen(self, flag) tw.canvas.setpen(True)
# Note: True will set the pen "down", enabling drawing;
# False will set the pen "up"
-# forward(self, n) lc.tw.canvas.forward(100)
+# forward(self, n) tw.canvas.forward(100)
# Note: Move the turtle forward 100 units
-# arc(self, a, r) lc.tw.canvas.arc(120, 50)
+# arc(self, a, r) tw.canvas.arc(120, 50)
# Note: Move the turtle along an arc of 120 degrees
# (clockwise) and radius of 50 units
-# setheading(self, a) lc.tw.canvas.setheading(180)
+# setheading(self, a) tw.canvas.setheading(180)
# Note: Set the turtle heading to 180
# (towards the bottom of the screen)
-# self.heading lc.tw.canvas.heading
+# self.heading tw.canvas.heading
# Note: The current heading
-# setpensize(self, n) lc.tw.canvas.setpensize(25)
+# setpensize(self, n) tw.canvas.setpensize(25)
# Note: Set the turtle pensize to 25 units
-# self.pensize lc.tw.canvas.pensize
+# self.pensize tw.canvas.pensize
# Note: The current pensize
-# setcolor(self, c) lc.tw.canvas.color(70)
+# setcolor(self, c) tw.canvas.color(70)
# Note: Set the pen color to 70 (blue)
-# self.color lc.tw.canvas.color
+# self.color tw.canvas.color
# Note: The current pen color
-# setshade(self, s) lc.tw.canvas.shade(50)
+# setshade(self, s) tw.canvas.shade(50)
# Note: Set the pen shade to 50
-# self.shade lc.tw.canvas.shade
+# self.shade tw.canvas.shade
# Note: The current pen shade
-# fillscreen(self, c, s) lc.tw.canvas.fillscreen(70, 90)
+# fillscreen(self, c, s) tw.canvas.fillscreen(70, 90)
# Note: Fill the screen with color 70, shade 90 (light blue)
-# setxy(self, x, y) lc.tw.canvas.setxy(100,100)
+# setxy(self, x, y) tw.canvas.setxy(100,100)
# Note: Move the turtle to position (100, 100)
-# self.xcor lc.tw.canvas.xcor
+# self.xcor tw.canvas.xcor
# Note: The current x coordinate of the turtle
# (scaled to current units)
-# self.ycor lc.tw.canvas.ycor
+# self.ycor tw.canvas.ycor
# Note: The current y coordinate of the turtle
# (scaled to current units)
-# self.set_turtle(name) lc.tw.canvas.set_turtle(1)
+# self.set_turtle(name) tw.canvas.set_turtle(1)
# Note: Set the current turtle to turtle '1'
-#
-#
+#
+#
# Other useful Python functions
# Module Example
# from math import pow pow(2,3) returns 2 to the 3rd power
@@ -118,34 +99,35 @@
# Note: See http://docs.python.org/library/math.html
# from time import localtime localtime().tm_hour returns the current hour
# Note: See http://docs.python.org/library/time.html
-# lc.heap.append(data) adds data to the heap
+# tw.lc.heap.append(data) adds data to the heap
# Note: See http://docs.python.org/tutorial/datastructures.html
-# data = lc.heap.pop(-1) pops data off the heap
+# data = tw.lc.heap.pop(-1) pops data off the heap
# Note: See http://docs.python.org/tutorial/datastructures.html
#
-def myblock(lc, x):
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the turtle will draw a dotted line of the length
+# of the numeric argument block docked to the Python block.
+
- ###########################################################################
- #
- # Draw a dotted line of length x.
- #
- ###########################################################################
+def myblock(tw, line_length):
+ ''' Draw a dotted line of length line_length. '''
- try: # make sure x is a number
- x = float(x)
+ try: # make sure line_length is a number
+ line_length = float(line_length)
except ValueError:
return
- if lc.tw.canvas.pendown:
+ if tw.canvas.pendown:
dist = 0
- while dist+lc.tw.canvas.pensize < x: # repeat drawing dots
- lc.tw.canvas.setpen(True)
- lc.tw.canvas.forward(1)
- lc.tw.canvas.setpen(False)
- lc.tw.canvas.forward((lc.tw.canvas.pensize*2)-1)
- dist += (lc.tw.canvas.pensize*2)
- lc.tw.canvas.forward(x-dist) # make sure we have moved exactly x
- lc.tw.canvas.setpen(True)
+ 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:
- lc.tw.canvas.forward(x)
+ tw.canvas.forward(line_length)
return
diff --git a/pysamples/grecord.py b/pysamples/grecord.py
new file mode 100644
index 0000000..84b1a5c
--- /dev/null
+++ b/pysamples/grecord.py
@@ -0,0 +1,227 @@
+#Copyright (c) 2008, Media Modifications Ltd.
+#Copyright (c) 2011, Walter Bender
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
+
+# Usage: Import this code into a Python (user-definable) block; Pass
+# it 'start' to start recording; 'stop' to stop recording; 'play' to
+# play back your recording; or 'save' to save your recording to the
+# Sugar Journal.
+
+
+def myblock(tw, arg):
+ ''' Record and playback a sound (Sugar only) '''
+ import os
+ import time
+
+ import gtk
+ import gst
+
+ import gobject
+ gobject.threads_init()
+
+ from TurtleArt.tautils import get_path
+ from TurtleArt.tagplay import play_audio_from_file
+ from sugar.datastore import datastore
+ from sugar import profile
+
+ from gettext import gettext as _
+
+ class Grecord:
+ ''' A class for creating a gstreamer session for recording audio. '''
+
+ def __init__(self, tw):
+ ''' Set up the stream. We save to a raw .wav file and then
+ convert the sound to .ogg for saving. '''
+ datapath = get_path(tw.parent, 'instance')
+ self.capture_file = os.path.join(datapath, 'output.wav')
+ self.save_file = os.path.join(datapath, 'output.ogg')
+ self._eos_cb = None
+
+ self._can_limit_framerate = False
+ self._recording = False
+
+ self._audio_transcode_handler = None
+ self._transcode_id = None
+
+ self._pipeline = gst.Pipeline("Record")
+ self._create_audiobin()
+ self._pipeline.add(self._audiobin)
+
+ bus = self._pipeline.get_bus()
+ bus.add_signal_watch()
+ bus.connect('message', self._bus_message_handler)
+
+ def _create_audiobin(self):
+ ''' Assemble all the pieces we need. '''
+ src = gst.element_factory_make("alsasrc", "absrc")
+
+ # attempt to use direct access to the 0,0 device, solving some A/V
+ # sync issues
+ src.set_property("device", "plughw:0,0")
+ hwdev_available = src.set_state(gst.STATE_PAUSED) != \
+ gst.STATE_CHANGE_FAILURE
+ src.set_state(gst.STATE_NULL)
+ if not hwdev_available:
+ src.set_property("device", "default")
+
+ srccaps = gst.Caps("audio/x-raw-int,rate=16000,channels=1,depth=16")
+
+ # guarantee perfect stream, important for A/V sync
+ rate = gst.element_factory_make("audiorate")
+
+ # without a buffer here, gstreamer struggles at the start of the
+ # recording and then the A/V sync is bad for the whole video
+ # (possibly a gstreamer/ALSA bug -- even if it gets caught up, it
+ # should be able to resync without problem)
+ queue = gst.element_factory_make("queue", "audioqueue")
+ queue.set_property("leaky", True) # prefer fresh data
+ queue.set_property("max-size-time", 5000000000) # 5 seconds
+ queue.set_property("max-size-buffers", 500)
+ queue.connect("overrun", self._log_queue_overrun)
+
+ enc = gst.element_factory_make("wavenc", "abenc")
+
+ sink = gst.element_factory_make("filesink", "absink")
+ sink.set_property("location", self.capture_file)
+
+ self._audiobin = gst.Bin("audiobin")
+ self._audiobin.add(src, rate, queue, enc, sink)
+
+ src.link(rate, srccaps)
+ gst.element_link_many(rate, queue, enc, sink)
+
+ def _log_queue_overrun(self, queue):
+ ''' We use a buffer, which may overflow. '''
+ cbuffers = queue.get_property("current-level-buffers")
+ cbytes = queue.get_property("current-level-bytes")
+ ctime = queue.get_property("current-level-time")
+
+ def is_recording(self):
+ ''' Are we recording? '''
+ return self._recording
+
+ def _get_state(self):
+ ''' What is the state of our gstreamer pipeline? '''
+ return self._pipeline.get_state()[1]
+
+ def start_recording_audio(self):
+ ''' Start the stream in order to start recording. '''
+ if self._get_state() == gst.STATE_PLAYING:
+ return
+ self._pipeline.set_state(gst.STATE_PLAYING)
+ self._recording = True
+
+ def stop_recording_audio(self):
+ ''' Stop recording and then convert the results into a
+ .ogg file using a new stream. '''
+ self._pipeline.set_state(gst.STATE_NULL)
+ self._recording = False
+
+ if not os.path.exists(self.capture_file) or \
+ os.path.getsize(self.capture_file) <= 0:
+ return
+
+ # Remove previous transcoding results.
+ if os.path.exists(self.save_file):
+ os.remove(self.save_file)
+
+ line = 'filesrc location=' + self.capture_file + ' name=audioFilesrc ! wavparse name=audioWavparse ! audioconvert name=audioAudioconvert ! vorbisenc name=audioVorbisenc ! oggmux name=audioOggmux ! filesink name=audioFilesink'
+ audioline = gst.parse_launch(line)
+
+ vorbis_enc = audioline.get_by_name('audioVorbisenc')
+
+ audioFilesink = audioline.get_by_name('audioFilesink')
+ audioFilesink.set_property("location", self.save_file)
+
+ audioBus = audioline.get_bus()
+ audioBus.add_signal_watch()
+ self._audio_transcode_handler = audioBus.connect(
+ 'message', self._onMuxedAudioMessageCb, audioline)
+ self._transcode_id = gobject.timeout_add(
+ 200, self._transcodeUpdateCb, audioline)
+ audioline.set_state(gst.STATE_PLAYING)
+
+ def _transcodeUpdateCb(self, pipe):
+ ''' Where are we in the transcoding process? '''
+ position, duration = self._query_position(pipe)
+ if position != gst.CLOCK_TIME_NONE:
+ value = position * 100.0 / duration
+ value = value/100.0
+ return True
+
+ def _query_position(self, pipe):
+ ''' Where are we in the stream? '''
+ try:
+ position, format = pipe.query_position(gst.FORMAT_TIME)
+ except:
+ position = gst.CLOCK_TIME_NONE
+
+ try:
+ duration, format = pipe.query_duration(gst.FORMAT_TIME)
+ except:
+ duration = gst.CLOCK_TIME_NONE
+
+ return (position, duration)
+
+ def _onMuxedAudioMessageCb(self, bus, message, pipe):
+ ''' Clean up at end of stream.'''
+ if message.type != gst.MESSAGE_EOS:
+ return True
+
+ gobject.source_remove(self._audio_transcode_handler)
+ self._audio_transcode_handler = None
+ gobject.source_remove(self._transcode_id)
+ self._transcode_id = None
+ pipe.set_state(gst.STATE_NULL)
+ pipe.get_bus().remove_signal_watch()
+ pipe.get_bus().disable_sync_message_emission()
+
+ os.remove(self.capture_file)
+ return False
+
+ def _bus_message_handler(self, bus, message):
+ ''' Handle any messages associated with the stream. '''
+ t = message.type
+ if t == gst.MESSAGE_EOS:
+ if self._eos_cb:
+ cb = self._eos_cb
+ self._eos_cb = None
+ cb()
+ elif t == gst.MESSAGE_ERROR:
+ # TODO: if we come out of suspend/resume with errors, then
+ # get us back up and running... TODO: handle "No space
+ # left on the resource.gstfilesink.c" err, debug =
+ # message.parse_error()
+ pass
+
+ # We store the audio-record stream instance as tw.grecord so that
+ # we can use it repeatedly.
+ if not hasattr(tw, 'grecord'):
+ tw.grecord = Grecord(tw)
+
+ # Sometime we need to parse multiple arguments, e.g., save, savename
+ save_name = _('Turtle Art') + ' ' + _('sound')
+ if type(arg) == type([]):
+ cmd = arg[0].lower()
+ if len(arg) > 1:
+ save_name = str(arg[1])
+ else:
+ cmd = arg.lower()
+
+ if cmd == 'start' or cmd == _('start').lower():
+ tw.grecord.start_recording_audio()
+ elif cmd == 'stop' or cmd == _('stop').lower():
+ tw.grecord.stop_recording_audio()
+ elif cmd == 'play' or cmd == _('play').lower():
+ play_audio_from_file(tw.lc, tw.grecord.save_file)
+ elif cmd == 'save' or cmd == _('save').lower():
+ if os.path.exists(tw.grecord.save_file) and tw.running_sugar:
+ dsobject = datastore.create()
+ dsobject.metadata['title'] = save_name
+ dsobject.metadata['icon-color'] = profile.get_color().to_string()
+ dsobject.metadata['mime_type'] = 'audio/ogg'
+ dsobject.set_file_path(tw.grecord.save_file)
+ datastore.write(dsobject)
+ dsobject.destroy()
diff --git a/pysamples/load_block.py b/pysamples/load_block.py
new file mode 100644
index 0000000..a457504
--- /dev/null
+++ b/pysamples/load_block.py
@@ -0,0 +1,78 @@
+#Copyright (c) 2011, Walter Bender
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
+
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the turtle will create a block at the current
+# location of the turtle. The first argument to the Python block
+# should be a string containing the name of the desired
+# block. Arguments to the block can be passed by expanding the Python
+# block to include up to two additional arguments. Note that the
+# turtle is moved to the bottom of the block after it is loaded in
+# order position another block to the bottom of the stack.
+
+# For example, try the following to place forward 100, right 90 on the canvas:
+# start
+# Python(forward, 100) <-- Python load_block.py expanded to two arguments
+# Python(right, 90) <-- Python load_block.py expanded to two arguments
+
+
+def myblock(tw, blkname):
+ ''' Load a block on to the canvas '''
+
+ from TurtleArt.tapalette import block_names, block_primitives, \
+ special_names, content_blocks
+ from TurtleArt.tautils import find_group
+
+ def make_block(tw, name, x, y, defaults):
+ x_pos = x + 20
+ y_pos = y + 20
+ tw._new_block(name, x_pos, y_pos, defaults)
+
+ # Find the block we just created and attach it to a stack.
+ tw.drag_group = None
+ spr = tw.sprite_list.find_sprite((x_pos, y_pos))
+ if spr is not None:
+ blk = tw.block_list.spr_to_block(spr)
+ if blk is not None:
+ tw.drag_group = find_group(blk)
+ tw._snap_to_dock()
+
+ # Disassociate new block from mouse.
+ tw.drag_group = None
+ return blk.height
+
+ def find_block(tw, blkname, x, y, defaults=None):
+ """ Create a new block. It is a bit more work than just calling
+ _new_block(). We need to:
+ (1) translate the label name into the internal block name;
+ (2) 'dock' the block onto a stack where appropriate; and
+ (3) disassociate the new block from the mouse. """
+
+ print blkname
+ for name in block_names:
+ # Translate label name into block/prim name.
+ if blkname in block_names[name]:
+ if (name in block_primitives and \
+ block_primitives[name] == name) or \
+ name in content_blocks:
+ return make_block(tw, name, x, y, defaults)
+ for name in special_names:
+ # Translate label name into block/prim name.
+ if blkname in special_names[name]:
+ return make_block(tw, name, x, y, defaults)
+ return -1
+
+ # Place the block at the active turtle (x, y) and move the turtle
+ # into position to place the next block in the stack.
+ x, y = tw.active_turtle.get_xy()
+ if type(blkname) == type([]):
+ name = blkname[0]
+ value = blkname[1:]
+ dy = int(find_block(tw, name, x, y, value))
+ else:
+ name = blkname
+ dy = int(find_block(tw, name, x, y))
+
+ tw.active_turtle.move((x, y - dy))
diff --git a/pysamples/load_journal_entry_to_heap.py b/pysamples/load_journal_entry_to_heap.py
index 7416554..3dd3bb5 100644
--- a/pysamples/load_journal_entry_to_heap.py
+++ b/pysamples/load_journal_entry_to_heap.py
@@ -1,35 +1,18 @@
-#Copyright (c) 2010, Walter Bender, Tony Forster
+#Copyright (c) 2010-11, Walter Bender, Tony Forster
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the chooser will be opened for selecting a file
+# from the Journal. The contents of that file will be loaded onto the
+# FILO heap.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
+def myblock(tw, x): # ignore second argument
+ ''' Load heap from journal (Sugar only) '''
-def myblock(lc, x):
-
- ###########################################################################
- #
- # Load heap from journal
- #
- ###########################################################################
-
- from tautils import chooser
+ from TurtleArt.tautils import chooser
# Choose a datastore object and push data to heap (Sugar only)
- chooser(lc.tw.parent, '', lc.push_file_data_to_heap)
+ chooser(tw.parent, '', tw.lc.push_file_data_to_heap)
diff --git a/pysamples/paste_to_heap.py b/pysamples/paste_to_heap.py
index 9255a93..0371078 100644
--- a/pysamples/paste_to_heap.py
+++ b/pysamples/paste_to_heap.py
@@ -1,33 +1,15 @@
-#Copyright (c) 2010, Walter Bender, Tony Forster
-
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
-
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
-
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
+#Copyright (c) 2010-11, Walter Bender, Tony Forster
# This procedure is invoked when the user-definable block on the "extras"
# palette is selected.
-def myblock(lc, x):
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the contents of the clipboard will be appended to
+# the FILO heap.
+
- ###########################################################################
- #
- # Paste from clipboard to heap
- #
- ###########################################################################
+def myblock(tw, x): # ignore second argument
+ ''' Paste from clipboard to heap '''
from gtk import Clipboard
from tautils import data_from_string
@@ -35,5 +17,5 @@ def myblock(lc, x):
text = Clipboard().wait_for_text()
if text is not None:
for val in data_from_string(text):
- lc.heap.append(val)
- lc.update_label_value('pop', val)
+ tw.lc.heap.append(val)
+ tw.lc.update_label_value('pop', val)
diff --git a/pysamples/push_mouse_event.py b/pysamples/push_mouse_event.py
index 485061f..b14315c 100644
--- a/pysamples/push_mouse_event.py
+++ b/pysamples/push_mouse_event.py
@@ -1,40 +1,26 @@
-#Copyright (c) 2009-10, Walter Bender, Tony Forster
+#Copyright (c) 2009-11, Walter Bender, Tony Forster
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the current mouse status will be pushed to the
+# FILO heap. If a mouse button event occurs, a y, x, and 1 are pushed
+# to the heap. If no button is pressed, 0 is pushed to the heap.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
+# To use these data, pop the heap in a compare block to determine if a
+# button has been pushed. If a 1 was popped from the heap, pop the x
+# and y coordinates.
-#
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
-def myblock(lc, x):
+def myblock(tw, x): # ignore second argument
+ ''' Push mouse event to stack '''
- ###########################################################################
- #
- # Push mouse event to stack
- #
- ###########################################################################
-
- if lc.tw.mouse_flag == 1:
+ if tw.mouse_flag == 1:
# push y first so x will be popped first
- lc.heap.append((lc.tw.canvas.height / 2) - lc.tw.mouse_y)
- lc.heap.append(lc.tw.mouse_x - (lc.tw.canvas.width / 2))
- lc.heap.append(1) # mouse event
- lc.tw.mouse_flag = 0
+ 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:
- lc.heap.append(0) # no mouse event
+ tw.lc.heap.append(0) # no mouse event
diff --git a/pysamples/push_time.py b/pysamples/push_time.py
index ae22684..5f86be4 100644
--- a/pysamples/push_time.py
+++ b/pysamples/push_time.py
@@ -1,37 +1,21 @@
-#Copyright (c) 2009-10, Walter Bender
+#Copyright (c) 2009-11, Walter Bender
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the current hour, minute, and second are pushed to
+# the FILO heap. To use these values, pop second, then minute, then
+# hour from the FILO.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
+def myblock(tw, x): # ignore second argument
+ ''' Push hours, minutes, seconds onto the FILO. '''
-def myblock(lc, 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 pop off of the FILO will be seconds.
- #
- ###########################################################################
- lc.heap.append(localtime().tm_hour)
- lc.heap.append(localtime().tm_min)
- lc.heap.append(localtime().tm_sec)
+ tw.lc.heap.append(localtime().tm_hour)
+ tw.lc.heap.append(localtime().tm_min)
+ tw.lc.heap.append(localtime().tm_sec)
diff --git a/pysamples/save_heap_to_journal_entry.py b/pysamples/save_heap_to_journal_entry.py
index c4f2d50..a06d4d0 100644
--- a/pysamples/save_heap_to_journal_entry.py
+++ b/pysamples/save_heap_to_journal_entry.py
@@ -1,33 +1,16 @@
-#Copyright (c) 2010, Walter Bender, Tony Forster
+#Copyright (c) 2010-11, Walter Bender, Tony Forster
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block; when
+# this code is run, the contents of the FILO heap are saved to a
+# Journal entry named by the value of the argument to the Python
+# block.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
-
-def myblock(lc, x):
-
- ###########################################################################
- #
- # Save heap to journal (Sugar only)
- #
- ###########################################################################
+def myblock(tw, title):
+ ''' Save heap to journal (Sugar only) '''
import os.path
from gettext import gettext as _
@@ -36,18 +19,19 @@ def myblock(lc, x):
from sugar.datastore import datastore
from sugar import profile
- from tautils import get_path, data_to_file
+ from TurtleArt.tautils import get_path, data_to_file
# Save JSON-encoded heap to temporary file
- heap_file = os.path.join(get_path(activity, 'instance'), str(x) + '.txt')
- data_to_file(lc.heap, heap_file)
+ heap_file = os.path.join(get_path(activity, 'instance'),
+ str(title) + '.txt')
+ data_to_file(tw.lc.heap, heap_file)
# Create a datastore object
dsobject = datastore.create()
# Write any metadata (specifically set the title of the file
# and specify that this is a plain text file).
- dsobject.metadata['title'] = str(x)
+ dsobject.metadata['title'] = str(title)
dsobject.metadata['icon-color'] = profile.get_color().to_string()
dsobject.metadata['mime_type'] = 'text/plain'
dsobject.set_file_path(heap_file)
diff --git a/pysamples/set_rgb.py b/pysamples/set_rgb.py
index f524ec6..d4baa48 100644
--- a/pysamples/set_rgb.py
+++ b/pysamples/set_rgb.py
@@ -1,50 +1,19 @@
-#Copyright (c) 2009-10, Walter Bender
+#Copyright (c) 2009-11, Walter Bender
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected and expanded to 3 arguments.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block.
+# First, expand the Python block to reveal three numerics arguments.
+# Set these values to the desired red, green, and blue. When the code
+# is run, the red, green, and blue values are used to set the pen
+# color.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-#
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected and expanded to 3 arguments.
-
-def myblock(lc, x):
-
- ###########################################################################
- #
- # Set rgb color from values
- #
- ###########################################################################
-
- # assuming x is an array [r, g, b]
- b = int(x[2])
- while b < 0:
- b += 256
- while b > 255:
- b -= 256
- g = int(x[1])
- while g < 0:
- g += 256
- while g > 255:
- g -= 256
- r = int(x[0])
- while r < 0:
- r += 256
- while r > 255:
- r -= 256
- rgb = "#%02x%02x%02x" % (r,g,b)
- lc.tw.canvas.fgcolor = lc.tw.canvas.cm.alloc_color(rgb)
+def myblock(tw, rgb_array):
+ ''' Set rgb color from values '''
+
+ rgb = "#%02x%02x%02x" % ((int(rgb_array[0]) % 256),
+ (int(rgb_array[1]) % 256),
+ (int(rgb_array[2]) % 256))
+ tw.canvas.fgcolor = tw.canvas.cm.alloc_color(rgb)
diff --git a/pysamples/sinewave.py b/pysamples/sinewave.py
index eea975d..4f14c4c 100644
--- a/pysamples/sinewave.py
+++ b/pysamples/sinewave.py
@@ -1,33 +1,15 @@
-#Copyright (c) 2010, Tony Forster
+#Copyright (c) 2010-11, Tony Forster
-#Permission is hereby granted, free of charge, to any person obtaining a copy
-#of this software and associated documentation files (the "Software"), to deal
-#in the Software without restriction, including without limitation the rights
-#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-#copies of the Software, and to permit persons to whom the Software is
-#furnished to do so, subject to the following conditions:
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
-#The above copyright notice and this permission notice shall be included in
-#all copies or substantial portions of the Software.
+# Usage: Import this code into a Python (user-definable) block and
+# pass a frequency in Hertz to the Python block. A tone will play over
+# the speaker at the specified frequency.
-#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-#THE SOFTWARE.
-# This procedure is invoked when the user-definable block on the "extras"
-# palette is selected.
-
-def myblock(lc, x):
-
- ###########################################################################
- #
- # Plays a sound at frequency x
- #
- ###########################################################################
+def myblock(tw, frequency):
+ ''' Plays a sound at frequency frequency '''
import os
- os.system('speaker-test -t sine -l 1 -f %d' % (int(x)))
+ os.system('speaker-test -t sine -l 1 -f %d' % (int(frequency)))
diff --git a/pysamples/speak.py b/pysamples/speak.py
new file mode 100644
index 0000000..30762a9
--- /dev/null
+++ b/pysamples/speak.py
@@ -0,0 +1,57 @@
+#Copyright (c) 2009-11, Walter Bender, Tony Forster
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
+
+# Usage: Import this code into a Python (user-definable) block and
+# pass a string to be read by the voice synthesizer. If a second
+# argument is passed, by expanding the Python block, it is used to specify
+# the pitch level of the speaker. Valid range is 0 to 99.
+
+
+def myblock(tw, arg):
+ ''' Text to speech '''
+
+ TABLE = {'af': 'afrikaans', 'cy': 'welsh-test', 'el': 'greek',
+ 'es': 'spanish', 'hi': 'hindi-test', 'hy': 'armenian',
+ 'ku': 'kurdish', 'mk': 'macedonian-test', 'pt': 'brazil',
+ 'sk': 'slovak', 'sw': 'swahili', 'bs': 'bosnian', 'da': 'danish',
+ 'en': 'english', 'fi': 'finnish', 'hr': 'croatian',
+ 'id': 'indonesian-test', 'la': 'latin', 'nl': 'dutch-test',
+ 'sq': 'albanian', 'ta': 'tamil', 'vi': 'vietnam-test',
+ 'ca': 'catalan', 'de': 'german', 'eo': 'esperanto',
+ 'fr': 'french', 'hu': 'hungarian', 'is': 'icelandic-test',
+ 'lv': 'latvian', 'no': 'norwegian', 'ro': 'romanian',
+ 'sr': 'serbian', 'zh': 'Mandarin', 'cs': 'czech', 'it': 'italian',
+ 'pl': 'polish', 'ru': 'russian_test', 'sv': 'swedish',
+ 'tr': 'turkish'}
+ import os
+
+ pitch = None
+ if type(arg) == type([]):
+ text = arg[0]
+ if len(arg) > 1:
+ pitch = int(arg[1])
+ if pitch > 99:
+ pitch = 99
+ elif pitch < 0:
+ pitch = 0
+ else:
+ text = arg
+
+ # Turtle Art numbers are passed as float,
+ # but they may be integer values.
+ if type(text) == float and int(text) == text:
+ text = int(text)
+
+ lang = os.environ['LANG'][0:2]
+ if lang in TABLE:
+ language_option = '-v ' + TABLE[lang]
+ else:
+ language_option = ''
+ if pitch is None:
+ os.system('espeak %s "%s" --stdout | aplay' % (language_option,
+ text))
+ else:
+ os.system('espeak %s "%s" -p "%s" --stdout | aplay' % (
+ language_option, text, pitch))
diff --git a/pysamples/svg_end_group.py b/pysamples/svg_end_group.py
new file mode 100644
index 0000000..e4682b3
--- /dev/null
+++ b/pysamples/svg_end_group.py
@@ -0,0 +1,17 @@
+#Copyright (c) 2009-11, Walter Bender
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected and expanded to 3 arguments.
+
+# Usage: Import this code into a Python (user-definable) block.
+# First, expand the Python block to reveal three numerics arguments.
+# Set these values to the desired red, green, and blue. When the code
+# is run, the red, green, and blue values are used to set the pen
+# color.
+
+
+def myblock(tw, x):
+ ''' Add end group to SVG output '''
+
+ tw.svg_string += '</g>'
+
diff --git a/pysamples/svg_start_group.py b/pysamples/svg_start_group.py
new file mode 100644
index 0000000..57500bc
--- /dev/null
+++ b/pysamples/svg_start_group.py
@@ -0,0 +1,17 @@
+#Copyright (c) 2009-11, Walter Bender
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected and expanded to 3 arguments.
+
+# Usage: Import this code into a Python (user-definable) block.
+# First, expand the Python block to reveal three numerics arguments.
+# Set these values to the desired red, green, and blue. When the code
+# is run, the red, green, and blue values are used to set the pen
+# color.
+
+
+def myblock(tw, x):
+ ''' Add start group to SVG output '''
+
+ tw.svg_string += '<g>'
+
diff --git a/pysamples/uturn.py b/pysamples/uturn.py
new file mode 100644
index 0000000..0b164a0
--- /dev/null
+++ b/pysamples/uturn.py
@@ -0,0 +1,35 @@
+#Copyright (c) 2011, Walter Bender
+
+# This procedure is invoked when the user-definable block on the
+# "extras" palette is selected.
+
+# Usage: Import this code into a Python (user-definable) block; when
+# it is run, a u-turn block will be added to the Turtle Palette. You
+# can use the u-turn block as you would any other block.
+
+
+def myblock(tw, arg):
+ ''' Add a uturn block to the 'turtle' palette '''
+
+ from TurtleArt.tapalette import make_palette, palette_name_to_index
+ from TurtleArt.talogo import primitive_dictionary
+ from gettext import gettext as _
+
+ # Choose a palette for the new block.
+ palette = make_palette('turtle')
+
+ # Create a new block prototype.
+ palette.add_block('uturn',
+ style='basic-style-extended-vertical',
+ label=_('uturn'),
+ prim_name='uturn',
+ help_string=_('make a uturn'))
+
+ # Add its primitive to the LogoCode dictionary.
+ tw.lc.def_prim('uturn', 0,
+ lambda self: primitive_dictionary['set'](
+ 'heading', tw.canvas.seth, tw.canvas.heading + 180))
+
+ # Regenerate the palette, which will now include the new block.
+ tw.show_toolbar_palette(palette_name_to_index('turtle'),
+ regenerate=True)