# -*- coding: utf-8 -*- #Copyright (c) 2012, Walter Bender # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA from time import time import os import glob from gettext import gettext as _ from plugins.plugin import Plugin from TurtleArt.tapalette import (make_palette, define_logo_function) from TurtleArt.talogo import (primitive_dictionary, logoerror) from TurtleArt.taconstants import (CONSTANTS, MACROS, KEY_DICT, MEDIA_SHAPES, REVERSE_KEY_DICT, SKIN_PATHS, BLOCKS_WITH_SKIN, PYTHON_SKIN, MEDIA_BLOCK2TYPE, VOICES) from TurtleArt.tautils import (debug_output, get_path, data_to_string, hat_on_top, listify, data_from_file) from TurtleArt.taprimitive import (ArgSlot, ConstantArg, Primitive) from TurtleArt.tatype import (TYPE_BOOL, TYPE_BOX, TYPE_CHAR, TYPE_INT, TYPE_FLOAT, TYPE_OBJECT, TYPE_STRING, TYPE_NUMBER) from TurtleArt.taturtle import Turtle class Turtle_blocks_extras(Plugin): """ a class for defining the extra palettes that distinguish Turtle Blocks from Turtle Art """ def __init__(self, turtle_window): Plugin.__init__(self) self.tw = turtle_window def setup(self): SKIN_PATHS.append('plugins/turtle_blocks_extras/images') self.heap = self.tw.lc.heap self.title_height = int((self.tw.canvas.height / 20) * self.tw.scale) # set up Turtle Block palettes self._flow_palette() self._sensor_palette() self._media_palette() self._extras_palette() self._portfolio_palette() self._myblocks_palette() # Palette definitions def _flow_palette(self): palette = make_palette('flow', colors=["#FFC000", "#A08000"], help_string=_('Palette of flow operators')) palette.add_block('while', style='clamp-style-boolean', label=_('while'), prim_name='while', default=[None, None], special_name=_('while'), help_string=_('do-while-True operator that uses \ boolean operators from Numbers palette')) self.tw.lc.def_prim( 'while', 2, Primitive(self.tw.lc.prim_loop, arg_descs=[ ArgSlot(TYPE_OBJECT, call_arg=False, wrapper=Primitive( Primitive.controller_while, arg_descs=[ArgSlot(TYPE_BOOL, call_arg=False)])), ArgSlot(TYPE_OBJECT)]), True) palette.add_block('until', style='clamp-style-until', label=_('until'), prim_name='until', default=[None, None], special_name=_('until'), help_string=_('do-until-True operator that uses \ boolean operators from Numbers palette')) self.tw.lc.def_prim( 'until', 2, Primitive(self.tw.lc.prim_loop, arg_descs=[ ArgSlot(TYPE_OBJECT, call_arg=False, # TODO can we use controller_while in # combination with not_? wrapper=Primitive( Primitive.controller_until, arg_descs=[ArgSlot(TYPE_BOOL, call_arg=False)])), ArgSlot(TYPE_OBJECT)]), True) palette.add_block('sandwichclamp', style='clamp-style-collapsible', label=' ', special_name=_('top'), prim_name='clamp', help_string=_('top of a collapsible stack')) self.tw.lc.def_prim('clamp', 1, Primitive(self.tw.lc.prim_clamp, arg_descs=[ArgSlot(TYPE_OBJECT)]), True) def _media_palette(self): palette = make_palette('media', colors=["#A0FF00", "#80A000"], help_string=_('Palette of media objects'), position=7, translation=_('media')) palette.add_block('journal', style='box-style-media', label=' ', default='None', special_name=_('journal'), help_string=_('Sugar Journal media object')) MEDIA_BLOCK2TYPE['journal'] = 'media' BLOCKS_WITH_SKIN.append('journal') MEDIA_SHAPES.append('journalsmall') MEDIA_SHAPES.append('journaloff') MEDIA_SHAPES.append('journalon') palette.add_block('audio', style='box-style-media', label=' ', special_name=_('audio'), default='None', help_string=_('Sugar Journal audio object')) BLOCKS_WITH_SKIN.append('audio') MEDIA_BLOCK2TYPE['audio'] = 'audio' MEDIA_SHAPES.append('audiosmall') MEDIA_SHAPES.append('audiooff') MEDIA_SHAPES.append('audioon') palette.add_block('video', style='box-style-media', label=' ', special_name=_('video'), default='None', help_string=_('Sugar Journal video object')) BLOCKS_WITH_SKIN.append('video') MEDIA_BLOCK2TYPE['video'] = 'video' MEDIA_SHAPES.append('videosmall') MEDIA_SHAPES.append('videooff') MEDIA_SHAPES.append('videoon') palette.add_block('description', style='box-style-media', label=' ', special_name=_('description'), default='None', help_string=_('Sugar Journal description field')) BLOCKS_WITH_SKIN.append('description') MEDIA_BLOCK2TYPE['description'] = 'descr' MEDIA_SHAPES.append('descriptionsmall') MEDIA_SHAPES.append('descriptionoff') MEDIA_SHAPES.append('descriptionon') palette.add_block('string', style='box-style', label=_('text'), default=_('text'), special_name=_('text'), help_string=_('string value')) palette.add_block('show', style='basic-style-1arg', label=_('show'), default=_('text'), prim_name='show', logo_command='label', help_string=_('draws text or show media from the \ Journal')) self.tw.lc.def_prim('show', 1, Primitive(self.tw.lc.show, arg_descs=[ArgSlot(TYPE_OBJECT), ConstantArg(True)])) palette.add_block('showaligned', hidden=True, colors=["#A0FF00", "#80A000"], style='basic-style-1arg', label=_('show aligned'), default=_('text'), prim_name='showaligned', logo_command='label', help_string=_('draws text or show media from the \ Journal')) self.tw.lc.def_prim('showaligned', 1, Primitive(self.tw.lc.show, arg_descs=[ArgSlot(TYPE_OBJECT), ConstantArg(False)])) palette.add_block('setscale', style='basic-style-1arg', label=_('set scale'), prim_name='setscale', default=33, logo_command='setlabelheight', help_string=_('sets the scale of media')) self.tw.lc.def_prim( 'setscale', 1, Primitive(self.tw.lc.set_scale, arg_descs=[ArgSlot(TYPE_NUMBER)], call_afterwards=lambda value: self.after_set( 'scale', value))) palette.add_block('savepix', style='basic-style-1arg', label=_('save picture'), prim_name='savepix', default=_('picture name'), help_string=_('saves a picture to the Sugar \ Journal')) self.tw.lc.def_prim('savepix', 1, Primitive(self.tw.save_as_image, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('savesvg', style='basic-style-1arg', label=_('save SVG'), prim_name='savesvg', default=_('picture name'), help_string=_('saves turtle graphics as an SVG file \ in the Sugar Journal')) self.tw.lc.def_prim('savesvg', 1, Primitive(self.tw.save_as_image, arg_descs=[ArgSlot(TYPE_STRING)], kwarg_descs={'svg': ConstantArg(True)})) palette.add_block('scale', style='box-style', label=_('scale'), prim_name='scale', value_block=True, logo_command='labelsize', help_string=_('holds current scale value')) self.tw.lc.def_prim('scale', 0, Primitive(self.tw.lc.get_scale, return_type=TYPE_NUMBER)) palette.add_block('mediawait', style='basic-style-extended-vertical', label=_('media wait'), prim_name='mediawait', help_string=_('wait for current video or audio to \ complete')) self.tw.lc.def_prim('mediawait', 0, self.tw.lc.media_wait, True) palette.add_block('mediastop', style='basic-style-extended-vertical', label=_('media stop'), prim_name='mediastop', help_string=_('stop video or audio')) self.tw.lc.def_prim('mediastop', 0, self.tw.lc.media_stop, True) palette.add_block('mediapause', style='basic-style-extended-vertical', label=_('media pause'), prim_name='mediapause', help_string=_('pause video or audio')) self.tw.lc.def_prim('mediapause', 0, self.tw.lc.media_pause, True) palette.add_block('mediaplay', style='basic-style-extended-vertical', label=_('media resume'), prim_name='mediaplay', help_string=_('resume playing video or audio')) self.tw.lc.def_prim('mediaplay', 0, self.tw.lc.media_play, True) palette.add_block('speak', style='basic-style-1arg', label=_('speak'), prim_name='speak', default=_('hello'), help_string=_('speaks text')) self.tw.lc.def_prim('speak', 1, Primitive(self.prim_speak, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('sinewave', style='basic-style-3arg', # TRANS: pitch, duration, amplitude label=[_('sinewave') + '\n\n', _('pitch'), _('amplitude'), _('duration')], prim_name='sinewave', default=[1000, 5000, 1], help_string=_('plays a sinewave at frequency, \ amplitude, and duration (in seconds)')) self.tw.lc.def_prim('sinewave', 3, Primitive(self.prim_sinewave, arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)])) def _sensor_palette(self): palette = make_palette('sensor', colors=["#FF6060", "#A06060"], help_string=_('Palette of sensor blocks'), position=6, translation=_('sensor')) palette.add_block('mousebutton', hidden=True, style='box-style', label=_('button down'), prim_name='mousebutton', value_block=True, help_string=_('returns 1 if mouse button is \ pressed')) self.tw.lc.def_prim('mousebutton', 0, Primitive(self.tw.get_mouse_flag, return_type=TYPE_NUMBER)) palette.add_block('mousebutton2', style='boolean-block-style', label=_('button down'), prim_name='mousebutton2', value_block=True, help_string=_('returns True if mouse button is \ pressed')) self.tw.lc.def_prim('mousebutton2', 0, Primitive(self.tw.get_mouse_button, return_type=TYPE_BOOL)) palette.add_block('mousex', style='box-style', label=_('mouse x'), prim_name='mousex', value_block=True, help_string=_('returns mouse x coordinate')) self.tw.lc.def_prim('mousex', 0, Primitive(self.tw.get_mouse_x, return_type=TYPE_NUMBER, call_afterwards=self.after_mouse_x)) palette.add_block('mousey', style='box-style', label=_('mouse y'), prim_name='mousey', value_block=True, help_string=_('returns mouse y coordinate')) self.tw.lc.def_prim('mousey', 0, Primitive(self.tw.get_mouse_y, return_type=TYPE_NUMBER, call_afterwards=self.after_mouse_y)) palette.add_block('kbinput', style='basic-style-extended-vertical', label=_('query keyboard'), prim_name='kbinput', help_string=_('query for keyboard input (results \ stored in keyboard block)')) self.tw.lc.def_prim('kbinput', 0, Primitive(self.tw.get_keyboard_input, call_afterwards=self.after_keypress)) palette.add_block('keyboard', style='box-style', label=_('keyboard'), prim_name='keyboard', value_block=True, logo_command='make "keyboard readchar', help_string=_('holds results of query-keyboard \ block as ASCII')) self.tw.lc.def_prim('keyboard', 0, Primitive(self.tw.get_keyboard, return_type=TYPE_NUMBER)) palette.add_block('readpixel', style='basic-style-extended-vertical', label=_('read pixel'), prim_name='readpixel', logo_command=':keyboard', help_string=_('RGB color under the turtle is pushed \ to the stack')) self.tw.lc.def_prim('readpixel', 0, Primitive(Turtle.read_pixel)) palette.add_block('see', style='box-style', label=_('turtle sees'), value_block=True, prim_name='see', help_string=_('returns the color that the turtle \ "sees"')) self.tw.lc.def_prim('see', 0, Primitive(Turtle.get_color_index, return_type=TYPE_NUMBER, call_afterwards=self.after_see)) palette.add_block('time', style='box-style', label=_('time'), prim_name='time', value_block=True, help_string=_('elapsed time (in seconds) since \ program started')) self.tw.lc.def_prim( 'time', 0, Primitive( Primitive.identity, return_type=TYPE_INT, arg_descs=[ ConstantArg( Primitive( int, arg_descs=[ConstantArg( Primitive(Primitive.minus, arg_descs=[ ConstantArg(Primitive(time)), ConstantArg(Primitive( self.tw.lc.get_start_time))]) )] ))], call_afterwards=self.after_time)) def _extras_palette(self): palette = make_palette('extras', colors=["#FF0000", "#A00000"], help_string=_('Palette of extra options'), position=8, translation=_('extras')) palette.add_block('push', style='basic-style-1arg', #TRANS: push adds a new item to the program stack label=_('push'), prim_name='push', logo_command='tapush', help_string=_('pushes value onto FILO (first-in \ last-out heap)')) self.tw.lc.def_prim( 'push', 1, Primitive(self.tw.lc.heap.append, arg_descs=[ArgSlot(TYPE_OBJECT)], call_afterwards=self.after_push)) define_logo_function('tapush', 'to tapush :foo\nmake "taheap fput \ :foo :taheap\nend\nmake "taheap []\n') palette.add_block('printheap', style='basic-style-extended-vertical', label=_('show heap'), prim_name='printheap', logo_command='taprintheap', help_string=_('shows values in FILO (first-in \ last-out heap)')) self.tw.lc.def_prim( 'printheap', 0, Primitive(self.tw.print_, arg_descs=[ConstantArg(Primitive(self.tw.lc.get_heap)), ConstantArg(False)])) define_logo_function('taprintheap', 'to taprintheap \nprint :taheap\n\ end\n') palette.add_block('clearheap', style='basic-style-extended-vertical', label=_('empty heap'), prim_name='clearheap', logo_command='taclearheap', help_string=_('emptys FILO (first-in-last-out \ heap)')) self.tw.lc.def_prim( 'clearheap', 0, Primitive(self.tw.lc.reset_heap, call_afterwards=self.after_pop)) define_logo_function('taclearheap', 'to taclearheap\nmake "taheap []\n\ end\n') palette.add_block('pop', style='box-style', #TRANS: pop removes a new item from the program stack label=_('pop'), prim_name='pop', value_block=True, logo_command='tapop', help_string=_('pops value off FILO (first-in \ last-out heap)')) self.tw.lc.def_prim( 'pop', 0, Primitive(self.tw.lc.heap.pop, return_type=TYPE_BOX, call_afterwards=self.after_pop)) define_logo_function('tapop', 'to tapop\nif emptyp :taheap [stop]\n\ make "tmp first :taheap\nmake "taheap butfirst :taheap\noutput :tmp\nend\n') palette.add_block('isheapempty', hidden=True, style='box-style', label=_('empty heap?'), prim_name='isheapempty', value_block=True, help_string=_('returns True if heap is empty')) self.tw.lc.def_prim( 'isheapempty', 0, Primitive(int, return_type=TYPE_INT, arg_descs=[ConstantArg( Primitive(Primitive.not_, return_type=TYPE_BOOL, arg_descs=[ConstantArg( Primitive(self.tw.lc.get_heap, return_type=TYPE_BOOL))]))])) palette.add_block('saveheap', style='basic-style-1arg', label=_('save heap to file'), default=_('filename'), prim_name='saveheap', help_string=_('saves FILO (first-in \ last-out heap) to a file')) self.tw.lc.def_prim('saveheap', 1, Primitive(self.tw.lc.save_heap, arg_descs=[ArgSlot(TYPE_OBJECT)])) if self.tw.running_sugar: palette.add_block('loadheap', style='basic-style-1arg', hidden=True, label=_('load heap from file'), default=_('filename'), prim_name='loadheap', help_string=_('loads FILO (first-in \ last-out heap) from a file')) # macro palette.add_block('loadheapfromjournal', style='basic-style-1arg', label=_('load heap from file'), help_string=_('loads FILO (first-in \ last-out heap) from a file')) else: palette.add_block('loadheap', style='basic-style-1arg', label=_('load heap from file'), default=_('filename'), prim_name='loadheap', help_string=_('loads FILO (first-in \ last-out heap) from a file')) self.tw.lc.def_prim('loadheap', 1, Primitive(self.tw.lc.load_heap, arg_descs=[ArgSlot(TYPE_OBJECT)], call_afterwards=self.after_push)) palette.add_block('isheapempty2', style='boolean-block-style', label=_('empty heap?'), prim_name='isheapempty2', value_block=True, help_string=_('returns True if heap is empty')) self.tw.lc.def_prim( 'isheapempty2', 0, # Python automatically converts the heap to a boolean in contexts # where a boolean is needed Primitive(Primitive.not_, return_type=TYPE_BOOL, arg_descs=[ConstantArg( Primitive(self.tw.lc.get_heap, return_type=TYPE_BOOL))])) palette.add_block('comment', style='basic-style-1arg', label=_('comment'), prim_name='comment', default=_('comment'), string_or_number=True, help_string=_('places a comment in your code')) self.tw.lc.def_prim( 'comment', 1, Primitive(Primitive.comment, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('print', style='basic-style-1arg', label=_('print'), prim_name='print', logo_command='label', string_or_number=True, help_string=_('prints value in status block at \ bottom of the screen')) self.tw.lc.def_prim( 'print', 1, Primitive(self.tw.print_, arg_descs=[ArgSlot(TYPE_OBJECT), ConstantArg(False)])) palette.add_block('chr', style='number-style-1arg', label='chr', prim_name='chr', help_string=_('Python chr operator')) self.tw.lc.def_prim( 'chr', 1, Primitive(chr, return_type=TYPE_CHAR, arg_descs=[ArgSlot(TYPE_INT)])) palette.add_block('int', style='number-style-1arg', label='int', prim_name='int', help_string=_('Python int operator')) self.tw.lc.def_prim( 'int', 1, # leave over the actual work to the type system, and just demand # that the argument be converted to an integer Primitive(Primitive.identity, return_type=TYPE_INT, arg_descs=[ArgSlot(TYPE_INT)])) palette.add_block('polar', style='basic-style-extended-vertical', label=_('polar'), prim_name='polar', help_string=_('displays polar coordinates')) self.tw.lc.def_prim('polar', 0, lambda self: self.tw.set_polar(True)) palette.add_block('myfunc1arg', style='number-style-var-arg', label=[_('Python'), 'f(x)', 'x'], prim_name='myfunction', default=['x', 100], string_or_number=True, help_string=_('a programmable block: used to add \ advanced single-variable math equations, e.g., sin(x)')) self.tw.lc.def_prim( 'myfunction', 2, Primitive(self.tw.lc.prim_myfunction, return_type=TYPE_FLOAT, arg_descs=[ArgSlot(TYPE_STRING), ArgSlot(TYPE_FLOAT)])) palette.add_block('myfunc2arg', hidden=True, colors=["#FF0000", "#A00000"], style='number-style-var-arg', label=[_('Python'), 'f(x,y)', ' '], prim_name='myfunction2', default=['x+y', 100, 100], string_or_number=True, help_string=_('a programmable block: used to add \ advanced multi-variable math equations, e.g., sqrt(x*x+y*y)')) self.tw.lc.def_prim( 'myfunction2', 3, Primitive(self.tw.lc.prim_myfunction, return_type=TYPE_FLOAT, arg_descs=[ArgSlot(TYPE_STRING), ArgSlot(TYPE_FLOAT), ArgSlot(TYPE_FLOAT)])) palette.add_block('myfunc3arg', hidden=True, colors=["#FF0000", "#A00000"], style='number-style-var-arg', label=[_('Python'), 'f(x,y,z)', ' '], prim_name='myfunction3', default=['x+y+z', 100, 100, 100], string_or_number=True, help_string=_('a programmable block: used to add \ advanced multi-variable math equations, e.g., sin(x+y+z)')) self.tw.lc.def_prim( 'myfunction3', 4, Primitive(self.tw.lc.prim_myfunction, return_type=TYPE_FLOAT, arg_descs=[ArgSlot(TYPE_STRING), ArgSlot(TYPE_FLOAT), ArgSlot(TYPE_FLOAT), ArgSlot(TYPE_FLOAT)])) palette.add_block('cartesian', style='basic-style-extended-vertical', label=_('Cartesian'), prim_name='cartesian', help_string=_('displays Cartesian coordinates')) self.tw.lc.def_prim('cartesian', 0, lambda self: self.tw.set_cartesian(True)) palette.add_block('userdefined', style='basic-style-var-arg', label=' ', prim_name='userdefined', string_or_number=True, special_name=_('Python block'), default=100, help_string=_('runs code found in the tamyblock.py \ module found in the Journal')) self.tw.lc.def_prim('userdefined', 1, Primitive(self.tw.lc.prim_myblock, arg_descs=[ArgSlot(TYPE_OBJECT)])) BLOCKS_WITH_SKIN.append('userdefined') PYTHON_SKIN.append('userdefined') palette.add_block('userdefined2args', hidden=True, colors=["#FF0000", "#A00000"], style='basic-style-var-arg', label=' ', prim_name='userdefined2', string_or_number=True, special_name=_('Python block'), default=[100, 100], help_string=_('runs code found in the tamyblock.py \ module found in the Journal')) self.tw.lc.def_prim('userdefined2', 2, Primitive(self.tw.lc.prim_myblock, arg_descs=[ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT)])) BLOCKS_WITH_SKIN.append('userdefined2args') PYTHON_SKIN.append('userdefined2args') palette.add_block('userdefined3args', hidden=True, colors=["#FF0000", "#A00000"], style='basic-style-var-arg', label=' ', prim_name='userdefined3', special_name=_('Python block'), default=[100, 100, 100], string_or_number=True, help_string=_('runs code found in the tamyblock.py \ module found in the Journal')) self.tw.lc.def_prim('userdefined3', 3, Primitive(self.tw.lc.prim_myblock, arg_descs=[ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT)])) BLOCKS_WITH_SKIN.append('userdefined3args') PYTHON_SKIN.append('userdefined3args') MEDIA_SHAPES.append('pythonsmall') MEDIA_SHAPES.append('pythonoff') MEDIA_SHAPES.append('pythonon') palette.add_block('getfromurl', style='number-style-1arg', #TRANS: URL is universal resource locator label=_('URL'), default=\ 'http://wiki.sugarlabs.org/images/2/2c/Logo_alt_3.svg', prim_name='getfromurl', help_string=\ _('gets a text string or an image from a URL')) self.tw.lc.def_prim('getfromurl', 1, Primitive(self.tw.lc.get_from_url, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('skin', hidden=True, colors=["#FF0000", "#A00000"], style='basic-style-1arg', label=_('turtle shell'), prim_name='skin', help_string=_("put a custom 'shell' on the turtle")) self.tw.lc.def_prim('skin', 1, Primitive(self.tw.lc.reskin, arg_descs=[ArgSlot(TYPE_OBJECT)])) # macro palette.add_block('reskin', style='basic-style-1arg', label=_('turtle shell'), help_string=_("put a custom 'shell' on the turtle")) palette.add_block('addturtle', style='basic-style-1arg', label=_('turtle'), prim_name='addturtle', default=1, string_or_number=True, help_string=_('chooses which turtle to command')) self.tw.lc.def_prim('addturtle', 1, Primitive(self.tw.lc.prim_turtle, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('turtlex', style='number-style-1arg', label=_('turtle x'), prim_name='turtlex', default=['Yertle'], help_string=_('Returns x coordinate of turtle')) self.tw.lc.def_prim( 'turtlex', 1, Primitive(self.tw.turtles.get_turtle_x, arg_descs=[ArgSlot(TYPE_OBJECT)], return_type=TYPE_BOX)) palette.add_block('turtley', style='number-style-1arg', label=_('turtle y'), prim_name='turtley', default=['Yertle'], help_string=_('Returns y coordinate of turtle')) self.tw.lc.def_prim( 'turtley', 1, Primitive(self.tw.turtles.get_turtle_y, arg_descs=[ArgSlot(TYPE_OBJECT)], return_type=TYPE_BOX)) palette.add_block('activeturtle', style='box-style', label=_('active turtle'), prim_name='activeturtle', value_block=True, help_string=_('the name of the active turtle')) self.tw.lc.def_prim( 'activeturtle', 0, Primitive(Turtle.get_name, return_type=TYPE_BOX)) palette.add_block('turtleh', style='number-style-1arg', label=_('turtle heading'), prim_name='turtleh', default=['Yertle'], help_string=_('Returns heading of turtle')) self.tw.lc.def_prim( 'turtleh', 1, Primitive(self.tw.turtles.get_turtle_heading, arg_descs=[ArgSlot(TYPE_OBJECT)], return_type=TYPE_BOX)) palette.add_block('sandwichclampcollapsed', hidden=True, style='clamp-style-collapsed', label=_('click to open'), prim_name='clamp', special_name=_('top'), help_string=_('top of a collapsed stack')) palette.add_block('loadpalette', style='basic-style-1arg', string_or_number=True, label=_('select palette'), prim_name='loadpalette', default=_('turtle'), help_string=_('selects a palette')) self.tw.lc.def_prim('loadpalette', 1, Primitive(self.tw.prim_load_palette, export_me=False, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('loadblock', style='basic-style-var-arg', label=_('load'), prim_name='loadblock', default=_('forward'), help_string=_('loads a block')) self.tw.lc.def_prim('loadblock', 1, Primitive(self.tw.prim_load_block, export_me=False, arg_descs=[ArgSlot(TYPE_STRING)])) palette.add_block('loadblock2arg', style='basic-style-var-arg', hidden=True, label=_('load'), prim_name='loadblock2', string_or_number=True, default=[_('forward'), 100], help_string=_('loads a block')) self.tw.lc.def_prim('loadblock2', 2, Primitive(self.tw.prim_load_block, export_me=False, arg_descs=[ArgSlot(TYPE_STRING), ArgSlot(TYPE_OBJECT)])) palette.add_block('loadblock3arg', style='basic-style-var-arg', hidden=True, label=_('load'), string_or_number=True, prim_name='loadblock3', default=[_('setxy'), 0, 0], help_string=_('loads a block')) self.tw.lc.def_prim('loadblock3', 3, Primitive(self.tw.prim_load_block, export_me=False, arg_descs=[ArgSlot(TYPE_STRING), ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT)])) def _portfolio_palette(self): palette = make_palette('portfolio', colors=["#0606FF", "#0606A0"], help_string=_('Palette of presentation \ templates'), position=9, translation=_('portfolio')) palette.add_block('hideblocks', style='basic-style-extended-vertical', label=_('hide blocks'), prim_name='hideblocks', help_string=_('declutters canvas by hiding blocks')) self.tw.lc.def_prim( 'hideblocks', 0, Primitive(self._prim_hideblocks, export_me=False)) palette.add_block('showblocks', style='basic-style-extended-vertical', label=_('show blocks'), prim_name='showblocks', help_string=_('restores hidden blocks')) self.tw.lc.def_prim( 'showblocks', 0, Primitive(self._prim_showblocks, export_me=False)) palette.add_block('fullscreen', style='basic-style-extended-vertical', label=_('Fullscreen').lower(), prim_name='fullscreen', help_string=_('hides the Sugar toolbars')) self.tw.lc.def_prim( 'fullscreen', 0, Primitive(self.tw.set_fullscreen, export_me=False)) primitive_dictionary['bulletlist'] = self._prim_list palette.add_block('list', hidden=True, colors=["#0606FF", "#0606A0"], style='bullet-style', label=_('list'), string_or_number=True, prim_name='bulletlist', default=['∙ ', '∙ '], help_string=_('presentation bulleted list')) self.tw.lc.def_prim('bulletlist', 1, primitive_dictionary['bulletlist'], True) # macros palette.add_block('picturelist', style='basic-style-extended', label=' ', help_string=_('presentation template: list of \ bullets')) MEDIA_SHAPES.append('list') palette.add_block('picture1x1a', style='basic-style-extended', label=' ', help_string=_('presentation template: select \ Journal object (no description)')) MEDIA_SHAPES.append('1x1a') palette.add_block('picture1x1', style='basic-style-extended', label=' ', help_string=_('presentation template: select \ Journal object (with description)')) MEDIA_SHAPES.append('1x1') palette.add_block('picture2x2', style='basic-style-extended', label=' ', help_string=_('presentation template: select four \ Journal objects')) MEDIA_SHAPES.append('2x2') palette.add_block('picture2x1', style='basic-style-extended', label=' ', help_string=_('presentation template: select two \ Journal objects')) MEDIA_SHAPES.append('2x1') palette.add_block('picture1x2', style='basic-style-extended', label=' ', help_string=_('presentation template: select two \ Journal objects')) MEDIA_SHAPES.append('1x2') # Display-dependent constants palette.add_block('leftpos', style='box-style', label=_('left'), prim_name='lpos', logo_command='lpos', help_string=_('xcor of left of screen')) self.tw.lc.def_prim( 'lpos', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('leftpos')])) palette.add_block('bottompos', style='box-style', label=_('bottom'), prim_name='bpos', logo_command='bpos', help_string=_('ycor of bottom of screen')) self.tw.lc.def_prim( 'bpos', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('bottompos')])) palette.add_block('width', style='box-style', label=_('width'), prim_name='hres', logo_command='width', help_string=_('the canvas width')) self.tw.lc.def_prim( 'hres', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('width')])) palette.add_block('rightpos', style='box-style', label=_('right'), prim_name='rpos', logo_command='rpos', help_string=_('xcor of right of screen')) self.tw.lc.def_prim( 'rpos', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('rightpos')])) palette.add_block('toppos', style='box-style', label=_('top'), prim_name='tpos', logo_command='tpos', help_string=_('ycor of top of screen')) self.tw.lc.def_prim( 'tpos', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('toppos')])) palette.add_block('height', style='box-style', label=_('height'), prim_name='vres', logo_command='height', help_string=_('the canvas height')) self.tw.lc.def_prim( 'vres', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('height')])) palette.add_block('titlex', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('title x'), logo_command='titlex', prim_name='titlex') self.tw.lc.def_prim( 'titlex', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('titlex')])) palette.add_block('titley', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('title y'), logo_command='titley', prim_name='titley') self.tw.lc.def_prim( 'titley', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('titley')])) palette.add_block('leftx', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('left x'), prim_name='leftx', logo_command='leftx') self.tw.lc.def_prim( 'leftx', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('leftx')])) palette.add_block('topy', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('top y'), prim_name='topy', logo_command='topy') self.tw.lc.def_prim( 'topy', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('topy')])) palette.add_block('rightx', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('right x'), prim_name='rightx', logo_command='rightx') self.tw.lc.def_prim( 'rightx', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('rightx')])) palette.add_block('bottomy', hidden=True, colors=["#0606FF", "#0606A0"], style='box-style', label=_('bottom y'), prim_name='bottomy', logo_command='bottomy') self.tw.lc.def_prim( 'bottomy', 0, Primitive(CONSTANTS.get, return_type=TYPE_INT, arg_descs=[ConstantArg('bottomy')])) def _myblocks_palette(self): ''' User-defined macros are saved as a json-encoded file; these get loaded into a palette on startup ''' if hasattr(self.tw, 'macros_path') and \ os.path.exists(self.tw.macros_path): files = glob.glob(os.path.join(self.tw.macros_path, '*.tb')) if len(files) > 0: palette = make_palette( 'myblocks', colors=["#FFFF00", "#A0A000"], help_string=_('Palette of user-defined operators'), translation=_('my blocks')) for tafile in files: data = data_from_file(tafile) name = os.path.basename(tafile)[:-3] # print 'loading macro %s' % (name) MACROS['user-defined-' + name] = hat_on_top(listify(data)) palette.add_block('user-defined-' + name, style='basic-style-extended-vertical', label=name) # Block primitives def after_keypress(self): if self.tw.lc.update_values: if self.tw.keypress in KEY_DICT: if KEY_DICT[self.tw.keypress] in REVERSE_KEY_DICT: self.tw.lc.update_label_value( 'keyboard', REVERSE_KEY_DICT[ KEY_DICT[self.tw.keypress]]) else: self.tw.lc.update_label_value( 'keyboard', chr(KEY_DICT[self.tw.keypress])) elif self.tw.keyboard > 0: self.tw.lc.update_label_value('keyboard', chr(self.tw.keyboard)) self.tw.keypress = '' def after_pop(self, *ignored_args): if self.tw.lc.update_values: if not self.tw.lc.heap: self.tw.lc.update_label_value('pop') else: self.tw.lc.update_label_value('pop', self.tw.lc.heap[-1]) def after_push(self, *ignored_args): if self.tw.lc.update_values: if not self.tw.lc.heap: self.tw.lc.update_label_value('pop') else: self.tw.lc.update_label_value('pop', self.tw.lc.heap[-1]) def prim_speak(self, text): """ Speak text """ if type(text) == float and int(text) == text: text = int(text) lang = os.environ['LANG'][0:2] if lang in VOICES: language_option = '-v ' + VOICES[lang] else: language_option = '' os.system('espeak %s "%s" --stdout | aplay' % (language_option, str(text))) if self.tw.sharing(): if language_option == '': event = 'S|%s' % (data_to_string([self.tw.nick, 'None', text])) else: event = 'S|%s' % (data_to_string([self.tw.nick, language_option, text])) self.tw.send_event(event) def prim_sinewave(self, pitch, amplitude, duration): """ Create a Csound score to play a sine wave. """ self.orchlines = [] self.scorelines = [] self.instrlist = [] try: pitch = abs(float(pitch)) amplitude = abs(float(amplitude)) duration = abs(float(duration)) except ValueError: self.tw.lc.stop_logo() raise logoerror("#notanumber") self._play_sinewave(pitch, amplitude, duration) if self.tw.running_sugar: path = os.path.join(get_path(self.tw.activity, 'instance'), 'tmp.csd') else: path = os.path.join('/tmp', 'tmp.csd') # Create a csound file from the score. self._audio_write(path) # Play the csound file. os.system('csound ' + path + ' > /dev/null 2>&1') def _play_sinewave(self, pitch, amplitude, duration, starttime=0, pitch_envelope=99, amplitude_envelope=100, instrument=1): pitenv = pitch_envelope ampenv = amplitude_envelope if not 1 in self.instrlist: self.orchlines.append("instr 1\n") self.orchlines.append("kpitenv oscil 1, 1/p3, p6\n") self.orchlines.append("aenv oscil 1, 1/p3, p7\n") self.orchlines.append("asig oscil p5*aenv, p4*kpitenv, p8\n") self.orchlines.append("out asig\n") self.orchlines.append("endin\n\n") self.instrlist.append(1) self.scorelines.append("i1 %s %s %s %s %s %s %s\n" % (str(starttime), str(duration), str(pitch), str(amplitude), str(pitenv), str(ampenv), str(instrument))) def _audio_write(self, file): """ Compile a .csd file. """ csd = open(file, "w") csd.write("\n\n") csd.write("\n") csd.write("-+rtaudio=alsa -odevaudio -m0 -d -b256 -B512\n") csd.write("\n\n") csd.write("\n\n") csd.write("sr=16000\n") csd.write("ksmps=50\n") csd.write("nchnls=1\n\n") for line in self.orchlines: csd.write(line) csd.write("\n\n\n") csd.write("\n\n") csd.write("f1 0 2048 10 1\n") csd.write("f2 0 2048 10 1 0 .33 0 .2 0 .143 0 .111\n") csd.write("f3 0 2048 10 1 .5 .33 .25 .2 .175 .143 .125 .111 .1\n") csd.write("f10 0 2048 10 1 0 0 .3 0 .2 0 0 .1\n") csd.write("f99 0 2048 7 1 2048 1\n") csd.write("f100 0 2048 7 0. 10 1. 1900 1. 132 0.\n") csd.write(self.scorelines.pop()) csd.write("e\n") csd.write("\n\n") csd.write("\n") csd.close() def after_mouse_x(self): """ Show mouse x coordinate """ if self.tw.lc.update_values: self.tw.lc.update_label_value('mousex', self.tw.get_mouse_x()) def after_mouse_y(self): """ Show mouse y coordinate """ if self.tw.lc.update_values: self.tw.lc.update_label_value('mousey', self.tw.get_mouse_y()) def after_see(self): """ Show color under turtle """ if self.tw.lc.update_values: self.tw.lc.update_label_value( 'see', self.tw.turtles.get_active_turtle().get_color_index()) def _prim_list(self, blklist): """ Expandable list block """ self.tw.lc.showlist(blklist) self.tw.lc.ireturn() yield True def after_time(self, elapsed_time): """ Update the label of the 'time' block after computing the new value. """ if self.tw.lc.update_values: self.tw.lc.update_label_value('time', elapsed_time) def _prim_hideblocks(self): """ hide blocks and show showblocks button """ self.tw.hideblocks() self.tw.lc.trace = 0 self.tw.step_time = 0 if self.tw.running_sugar: self.tw.activity.stop_turtle_button.set_icon("hideshowoff") self.tw.activity.stop_turtle_button.set_tooltip(_('Show blocks')) def _prim_showblocks(self): """ show blocks and show stop turtle button """ self.tw.showblocks() self.tw.lc.trace = 1 self.tw.step_time = 3 if self.tw.running_sugar: self.tw.activity.stop_turtle_button.set_icon("stopiton") self.tw.activity.stop_turtle_button.set_tooltip(_('Stop turtle')) def after_set(self, name, value=None): ''' Update the associated value blocks ''' if value is not None: if self.tw.lc.update_values: self.tw.lc.update_label_value(name, value)