Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/tabasics.py
diff options
context:
space:
mode:
authorWalter Bender <walter.bender@gmail.com>2011-03-01 22:54:55 (GMT)
committer Walter Bender <walter.bender@gmail.com>2011-03-01 22:54:55 (GMT)
commitea3a04bb097a57621224e9894e02b1b0d13895cc (patch)
treec87a133ea7e687c2a0152cebe083b1c4251efaa2 /TurtleArt/tabasics.py
parent05f2c191de9deee3624447e9fa1720a6c5aae506 (diff)
refactoring of palette and block generation: a class for each palette and block rather than giant dictionaries
Diffstat (limited to 'TurtleArt/tabasics.py')
-rw-r--r--TurtleArt/tabasics.py1199
1 files changed, 1199 insertions, 0 deletions
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py
new file mode 100644
index 0000000..7d29f5e
--- /dev/null
+++ b/TurtleArt/tabasics.py
@@ -0,0 +1,1199 @@
+# -*- coding: utf-8 -*-
+#Copyright (c) 2011, 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 file contains the constants that by-in-large determine the
+behavior of Turtle Art. Notably, the block palettes are defined
+below. If you want to add a new block to Turtle Art, you could
+simply add a block of code to this file or to turtle_block_plugin.py,
+which contains additional blocks. (Even better, write your own plugin!!)
+
+For example, if we want to add a new turtle command, 'uturn', we'd
+make the following changes:
+
+ b = Primitive('uturn')
+ b.set_palette('turtle') # the palette to place it in
+ b.set_style('basic-style') # the block style
+ b.set_label(_('u-turn')) # the label that will appear on the block
+ b.set_prim_name('uturn') # an intern name for the primitive
+ b.set_help(_('turns the turtle 180 degrees')) # a help message
+
+ # def_prim takes 3 arguments: the primitive name, the number of
+ # of arguments, 0 in this case, and the function to call.
+ # We are using a special method, 'set', that will update the label
+ # of the heading block as well as the heading itself. _prim_set
+ # also takes arguments: the name of the block whose label needs to
+ # be updated, the function call to change the value, and the new
+ # value, in the case, the current heading + 180
+ self.tw.lc._def_prim('uturn', 0,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'heading', self.tw.canvas.seth, self.tw.canvas.heading + 180))
+ b.add_prim()
+
+That's it. When you next run Turtle Art, you will have a 'uturn' block
+on the Turtle Palette.
+
+Adding a new palette is simply a matter of:
+ p = Palette('turtle', ["#00FF00", "#00A000"]) # assign name and colors
+ p.set_help(_('Palette of turtle commands')) # and a help message
+ p.add_palette()
+
+However you will have to create icons for the palette-selector
+buttons. These are kept in the icons subdirectory. You need two icons:
+yourpalettenameoff.svg and yourpalettenameon.svg, where
+yourpalettename is the same string as the entry you added to the
+PALETTE_NAMES list. Note that the icons should be the same size
+(55x55) as the others. This is the default icon size for Sugar
+toolbars.
+
+"""
+
+from time import time
+from math import sqrt
+from random import uniform
+
+from gettext import gettext as _
+
+from taprimitive import Palette, Primitive
+from talogo import PLUGIN_DICTIONARY, VALUE_BLOCKS, logoerror
+from taconstants import DEFAULT_SCALE, CONSTANTS, BLACK, WHITE
+from tautils import convert, chr_to_ord, round_int, strtype
+
+
+def _num_type(x):
+ """ Is x a number type? """
+ if type(x) == int:
+ return True
+ if type(x) == float:
+ return True
+ if type(x) == ord:
+ return True
+ return False
+
+def _millisecond():
+ """ Current time in milliseconds """
+ return time() * 1000
+
+
+class Palettes():
+ """ a class for storing the palettes of blocks """
+
+ def __init__(self, parent):
+ self.tw = parent
+
+ p = Palette('turtle', ["#00FF00", "#00A000"])
+ p.set_help(_('Palette of turtle commands'))
+ p.add_palette()
+ self._turtle_palette()
+
+ p = Palette('pen', ["#00FFFF", "#00A0A0"])
+ p.set_help(_('Palette of pen commands'))
+ p.add_palette()
+ self._pen_palette()
+
+ p = Palette('colors', ["#00FFFF", "#00A0A0"])
+ p.set_help(_('Palette of pen colors'))
+ p.add_palette()
+ self._color_palette()
+
+ p = Palette('numbers', ["#FF00FF", "#A000A0"])
+ p.set_help(_('Palette of numeric operators'))
+ p.add_palette()
+ self._numbers_palette()
+
+ p = Palette('flow', ["#FFC000", "#A08000"])
+ p.set_help(_('Palette of flow operators'))
+ p.add_palette()
+ self._flow_palette()
+
+ p = Palette('blocks', ["#FFFF00", "#A0A000"])
+ p.set_help(_('Palette of variable blocks'))
+ p.add_palette()
+ self._blocks_palette()
+
+ p = Palette('trash', ["#FFFF00", "#A0A000"])
+ p.add_palette()
+ self._trash_palette()
+
+ # Palette definitions
+
+ def _turtle_palette(self):
+ b = Primitive('forward')
+ b.set_palette('turtle')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('forward'))
+ b.set_prim_name('forward')
+ b.set_default(100)
+ b.set_help(_('moves turtle forward'))
+ PLUGIN_DICTIONARY['move'] = self._prim_move
+ self.tw.lc._def_prim('forward', 1,
+ lambda self, x: PLUGIN_DICTIONARY['move'](
+ self.tw.canvas.forward, x))
+ b.add_prim()
+
+ b = Primitive('back')
+ b.set_palette('turtle')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('back'))
+ b.set_prim_name('back')
+ b.set_default(100)
+ b.set_help(_('moves turtle backward'))
+ self.tw.lc._def_prim('back', 1,
+ lambda self, x: PLUGIN_DICTIONARY['move'](
+ self.tw.canvas.forward, -x))
+ b.add_prim()
+
+ b = Primitive('clean')
+ b.set_palette('turtle')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('clean'))
+ b.set_prim_name('clean')
+ b.set_help(_('clears the screen and reset the turtle'))
+ PLUGIN_DICTIONARY['clean'] = self._prim_clear
+ self.tw.lc._def_prim('clean', 0,
+ lambda self: PLUGIN_DICTIONARY['clean']())
+ b.add_prim()
+
+ b = Primitive('left')
+ b.set_palette('turtle')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('left'))
+ b.set_prim_name('left')
+ b.set_default(90)
+ b.set_help(_('turns turtle counterclockwise (angle in degrees'))
+ PLUGIN_DICTIONARY['right'] = self._prim_right
+ self.tw.lc._def_prim('right', 1,
+ lambda self, x: PLUGIN_DICTIONARY['right'](-x))
+ b.add_prim()
+
+ b = Primitive('right')
+ b.set_palette('turtle')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('right'))
+ b.set_prim_name('right')
+ b.set_default(90)
+ b.set_help(_('turns turtle clockwise (angle in degrees'))
+ self.tw.lc._def_prim('right', 1,
+ lambda self, x: PLUGIN_DICTIONARY['right'](x))
+ b.add_prim()
+
+ b = Primitive('arc')
+ b.set_palette('turtle')
+ b.set_style('basic-style-2arg')
+ b.set_label([_('arc'), _('angle'), _('radius')])
+ b.set_prim_name('arc')
+ b.set_default([90, 100])
+ b.set_help(_('moves turtle along an arc'))
+ PLUGIN_DICTIONARY['arc'] = self._prim_arc
+ self.tw.lc._def_prim('arc', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['arc'](
+ self.tw.canvas.arc, x, y))
+ b.add_prim()
+
+ b = Primitive('setxy2')
+ b.set_palette('turtle')
+ b.set_style('basic-style-2arg')
+ b.set_label([_('set xy'), _('x'), _('y')])
+ b.set_prim_name('setxy2')
+ b.set_default([0, 0])
+ b.set_help(_('moves turtle to position xcor, ycor; (0, 0) is in the center of the screen.'))
+ self.tw.lc._def_prim('setxy2', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['move'](
+ self.tw.canvas.setxy, x, y))
+ b.add_prim()
+
+ b = Primitive('setxy') # Depreciated
+ b.set_style('basic-style-2arg')
+ b.set_label([_('set xy'), _('x'), _('y')])
+ b.set_prim_name('setxy')
+ b.set_default([0, 0])
+ b.set_help(_('moves turtle to position xcor, ycor; (0, 0) is in the center of the screen.'))
+ self.tw.lc._def_prim('setxy', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['move'](
+ self.tw.canvas.setxy, x, y, pendown=False))
+ b.add_prim()
+
+ b = Primitive('seth')
+ b.set_palette('turtle')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set heading'))
+ b.set_prim_name('seth')
+ b.set_default(0)
+ b.set_help(_('sets the heading of the turtle (0 is towards the top of the screen.'))
+ PLUGIN_DICTIONARY['set'] = self._prim_set
+ self.tw.lc._def_prim('seth', 1,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'heading', self.tw.canvas.seth, x))
+ b.add_prim()
+
+ b = Primitive('xcor')
+ b.set_palette('turtle')
+ b.set_style('box-style')
+ b.set_label(_('xcor'))
+ b.set_help(_('holds current x-coordinate value of the turtle (can be used in place of a number block'))
+ b.set_value_block(True)
+ b.set_prim_name('xcor')
+ self.tw.lc._def_prim(
+ 'xcor', 0, lambda self: self.tw.canvas.xcor / self.tw.coord_scale)
+ b.add_prim()
+
+ b = Primitive('ycor')
+ b.set_palette('turtle')
+ b.set_style('box-style')
+ b.set_label(_('ycor'))
+ b.set_help(_('holds current y-coordinate value of the turtle (can be used in place of a number block'))
+ b.set_value_block(True)
+ b.set_prim_name('ycor')
+ self.tw.lc._def_prim(
+ 'ycor', 0, lambda self: self.tw.canvas.ycor / self.tw.coord_scale)
+ b.add_prim()
+
+ b = Primitive('heading')
+ b.set_palette('turtle')
+ b.set_style('box-style')
+ b.set_label(_('heading'))
+ b.set_help(_('holds current heading value of the turtle (can be used in place of a number block'))
+ b.set_value_block(True)
+ b.set_prim_name('heading')
+ self.tw.lc._def_prim(
+ 'heading', 0, lambda self: self.tw.canvas.heading)
+ b.add_prim()
+
+ def _pen_palette(self):
+ b = Primitive('penup')
+ b.set_palette('pen')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('pen up'))
+ b.set_prim_name('penup')
+ b.set_help(_('Turtle will not draw when moved.'))
+ self.tw.lc._def_prim('penup', 0,
+ lambda self: self.tw.canvas.setpen(False))
+ b.add_prim()
+
+ b = Primitive('pendown')
+ b.set_palette('pen')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('pen down'))
+ b.set_prim_name('pendown')
+ b.set_help(_('Turtle will draw when moved.'))
+ self.tw.lc._def_prim('pendown', 0,
+ lambda self: self.tw.canvas.setpen(True))
+ b.add_prim()
+
+ b = Primitive('setpensize')
+ b.set_palette('pen')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set pen size'))
+ b.set_prim_name('setpensize')
+ b.set_default(5)
+ b.set_help(_('sets size of the line drawn by the turtle'))
+ self.tw.lc._def_prim('setpensize', 1,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'pensize', self.tw.canvas.setpensize, x))
+ b.add_prim()
+
+ b = Primitive('fillscreen')
+ b.set_palette('pen')
+ b.set_style('basic-style-2arg')
+ b.set_label([_('fill screen'), _('color'), _('shade')])
+ b.set_prim_name('fillscreen')
+ b.set_default([60, 80])
+ b.set_help(_('fills the background with (color, shade)'))
+ self.tw.lc._def_prim('fillscreen', 2,
+ lambda self, x, y: self.tw.canvas.fillscreen(x, y))
+ b.add_prim()
+
+ b = Primitive('pensize')
+ b.set_palette('pen')
+ b.set_style('box-style')
+ b.set_label(_('pen size'))
+ b.set_help(_('holds current pen size (can be used in place of a number block)'))
+ b.set_value_block(True)
+ b.set_prim_name('pensize')
+ self.tw.lc._def_prim('pensize', 0, lambda self: self.tw.canvas.pensize)
+ b.add_prim()
+
+ b = Primitive('startfill')
+ b.set_palette('pen')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('start fill'))
+ b.set_prim_name('startfill')
+ b.set_help(_('starts filled polygon (used with end fill block)'))
+ self.tw.lc._def_prim('startfill', 0,
+ lambda self: self.tw.canvas.start_fill())
+ b.add_prim()
+
+ b = Primitive('stopfill')
+ b.set_palette('pen')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('end fill'))
+ b.set_prim_name('stopfill')
+ b.set_help(_('completes filled polygon (used with start fill block)'))
+ self.tw.lc._def_prim('stopfill', 0,
+ lambda self: self.tw.canvas.stop_fill())
+ b.add_prim()
+
+ def _color_palette(self):
+ b = Primitive('setcolor')
+ b.set_palette('colors')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set color'))
+ b.set_prim_name('setcolor')
+ b.set_default(0)
+ b.set_help(_('sets color of the line drawn by the turtle'))
+ self.tw.lc._def_prim('setcolor', 1,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'color', self.tw.canvas.setcolor, x))
+ b.add_prim()
+
+ b = Primitive('settextcolor') # depreciated
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set text color'))
+ b.set_prim_name('settextcolor')
+ b.set_default(0)
+ b.set_help(_('sets color of text drawn by the turtle'))
+ self.tw.lc._def_prim('settextcolor', 1,
+ lambda self, x: self.tw.canvas.settextcolor(x))
+ b.add_prim()
+
+ b = Primitive('setshade')
+ b.set_palette('colors')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set shade'))
+ b.set_prim_name('setshade')
+ b.set_default(50)
+ b.set_help(_('sets shade of the line drawn by the turtle'))
+ self.tw.lc._def_prim('setshade', 1,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'shade', self.tw.canvas.setshade, x))
+ b.add_prim()
+
+ b = Primitive('setgray')
+ b.set_palette('colors')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('set gray'))
+ b.set_prim_name('setgray')
+ b.set_default(100)
+ b.set_help(_('sets gray level of the line drawn by the turtle'))
+ self.tw.lc._def_prim('setgray', 1,
+ lambda self, x: PLUGIN_DICTIONARY['set'](
+ 'gray', self.tw.canvas.setgray, x))
+ b.add_prim()
+
+ b = Primitive('color')
+ b.set_palette('colors')
+ b.set_style('box-style')
+ b.set_label(_('color'))
+ b.set_help(_('holds current pen color (can be used in place of a number block)'))
+ b.set_value_block(True)
+ b.set_prim_name('color')
+ self.tw.lc._def_prim('color', 0, lambda self: self.tw.canvas.color)
+ b.add_prim()
+
+ b = Primitive('shade')
+ b.set_palette('colors')
+ b.set_style('box-style')
+ b.set_label(_('shade'))
+ b.set_help(_('holds current pen shade'))
+ b.set_value_block(True)
+ b.set_prim_name('shade')
+ self.tw.lc._def_prim('shade', 0, lambda self: self.tw.canvas.shade)
+ b.add_prim()
+
+ b = Primitive('gray')
+ b.set_palette('colors')
+ b.set_style('box-style')
+ b.set_label(_('gray'))
+ b.set_help(_('holds current gray level (can be used in place of a number block)'))
+ b.set_value_block(True)
+ b.set_prim_name('gray')
+ self.tw.lc._def_prim('gray', 0, lambda self: self.tw.canvas.gray)
+ b.add_prim()
+
+ self._make_constant('red', 'colors', CONSTANTS['red'])
+ self._make_constant('orange', 'colors', CONSTANTS['orange'])
+ self._make_constant('yellow', 'colors', CONSTANTS['yellow'])
+ self._make_constant('green', 'colors', CONSTANTS['green'])
+ self._make_constant('cyan', 'colors', CONSTANTS['cyan'])
+ self._make_constant('blue', 'colors', CONSTANTS['blue'])
+ self._make_constant('purple', 'colors', CONSTANTS['purple'])
+ self._make_constant('white', 'colors', WHITE)
+ self._make_constant('black', 'colors', BLACK)
+
+ def _numbers_palette(self):
+ b = Primitive('plus2')
+ b.set_palette('numbers')
+ b.set_style('number-style')
+ b.set_label('+')
+ b.set_special_name(_('plus'))
+ b.set_prim_name('plus')
+ b.set_help(_('adds two alphanumeric inputs'))
+ PLUGIN_DICTIONARY['plus'] = self._prim_plus
+ self.tw.lc._def_prim(
+ 'plus', 2, lambda self, x, y: PLUGIN_DICTIONARY['plus'](x, y))
+ b.add_prim()
+
+ b = Primitive('minus2')
+ b.set_palette('numbers')
+ b.set_style('number-style-porch')
+ b.set_label('–')
+ b.set_special_name(_('minus'))
+ b.set_prim_name('minus')
+ b.set_help(_('subtracts bottom numeric input from top numeric input'))
+ PLUGIN_DICTIONARY['minus'] = self._prim_minus
+ self.tw.lc._def_prim(
+ 'minus', 2, lambda self, x, y: PLUGIN_DICTIONARY['minus'](x, y))
+ b.add_prim()
+
+ b = Primitive('product2')
+ b.set_palette('numbers')
+ b.set_style('number-style')
+ b.set_label('×')
+ b.set_special_name(_('multiply'))
+ b.set_prim_name('product')
+ b.set_help(_('multiplies two numeric inputs'))
+ PLUGIN_DICTIONARY['product'] = self._prim_product
+ self.tw.lc._def_prim(
+ 'product', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['product'](x, y))
+ b.add_prim()
+
+ b = Primitive('division2')
+ b.set_palette('numbers')
+ b.set_style('number-style-porch')
+ b.set_label('/')
+ b.set_special_name(_('divide'))
+ b.set_prim_name('division')
+ b.set_help(_('divides top numeric input (numerator) by bottom numeric input (denominator)'))
+ PLUGIN_DICTIONARY['division'] = self._prim_careful_divide
+ self.tw.lc._def_prim(
+ 'division', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['division'](x, y))
+ b.add_prim()
+
+ b = Primitive('identity2')
+ b.set_palette('numbers')
+ b.set_style('number-style-1strarg')
+ b.set_label('←')
+ b.set_special_name(_('identity'))
+ b.set_prim_name('id')
+ b.set_help(_('identity operator used for extending blocks'))
+ PLUGIN_DICTIONARY['id'] = self._prim_identity
+ self.tw.lc._def_prim('id', 1,
+ lambda self, x: PLUGIN_DICTIONARY['id'](x))
+ b.add_prim()
+
+ b = Primitive('remainder2')
+ b.set_palette('numbers')
+ b.set_style('number-style-porch')
+ b.set_label(_('mod'))
+ b.set_special_name(_('mod'))
+ b.set_prim_name('remainder')
+ b.set_help(_('modular (remainder) operator'))
+ PLUGIN_DICTIONARY['remainder'] = self._prim_mod
+ self.tw.lc._def_prim('remainder', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['remainder'](x, y))
+ b.add_prim()
+
+ b = Primitive('sqrt')
+ b.set_palette('numbers')
+ b.set_style('number-style-1arg')
+ b.set_label(_('√'))
+ b.set_special_name(_('square root'))
+ b.set_prim_name('sqrt')
+ b.set_help(_('calculates square root'))
+ PLUGIN_DICTIONARY['sqrt'] = self._prim_sqrt
+ self.tw.lc._def_prim('sqrt', 1,
+ lambda self, x: PLUGIN_DICTIONARY['sqrt'](x))
+ b.add_prim()
+
+ b = Primitive('random')
+ b.set_palette('numbers')
+ b.set_style('number-style-block')
+ b.set_label([_('random'), _('min'), _('max')])
+ b.set_default([0, 100])
+ b.set_prim_name('random')
+ b.set_help(_('returns random number between minimum (top) and maximum (bottom) values'))
+ PLUGIN_DICTIONARY['random'] = self._prim_random
+ self.tw.lc._def_prim(
+ 'random', 2, lambda self, x, y: PLUGIN_DICTIONARY['random'](x, y))
+ b.add_prim()
+
+ b = Primitive('number')
+ b.set_palette('numbers')
+ b.set_style('box-style')
+ b.set_label('100')
+ b.set_default(100)
+ b.set_special_name(_('number'))
+ b.set_help('used as numeric input in mathematic operators')
+ b.add_prim()
+
+ b = Primitive('greater2')
+ b.set_palette('numbers')
+ b.set_style('compare-porch-style')
+ b.set_label('>')
+ b.set_special_name(_('greater than'))
+ b.set_prim_name('greater?')
+ b.set_help(_('logical greater-than operator'))
+ PLUGIN_DICTIONARY['more'] = self._prim_more
+ self.tw.lc._def_prim(
+ 'greater?', 2, lambda self, x, y: PLUGIN_DICTIONARY['more'](x, y))
+ b.add_prim()
+
+ b = Primitive('less2')
+ b.set_palette('numbers')
+ b.set_style('compare-porch-style')
+ b.set_label('<')
+ b.set_special_name(_('less than'))
+ b.set_prim_name('less?')
+ b.set_help(_('logical less-than operator'))
+ PLUGIN_DICTIONARY['less'] = self._prim_less
+ self.tw.lc._def_prim(
+ 'less?', 2, lambda self, x, y: PLUGIN_DICTIONARY['less'](x, y))
+ b.add_prim()
+
+ b = Primitive('equal2')
+ b.set_palette('numbers')
+ b.set_style('compare-style')
+ b.set_label('=')
+ b.set_special_name(_('equal'))
+ b.set_prim_name('equal?')
+ b.set_help(_('logical equal-to operator'))
+ PLUGIN_DICTIONARY['equal'] = self._prim_equal
+ self.tw.lc._def_prim(
+ 'equal?', 2, lambda self, x, y: PLUGIN_DICTIONARY['equal'](x, y))
+ b.add_prim()
+
+ b = Primitive('not')
+ b.set_palette('numbers')
+ b.set_style('not-style')
+ b.set_label(_('not'))
+ b.set_prim_name('not')
+ b.set_help(_('logical NOT operator'))
+ self.tw.lc._def_prim('not', 1, lambda self, x: not x)
+ b.add_prim()
+
+ b = Primitive('and2')
+ b.set_palette('numbers')
+ b.set_style('boolean-style')
+ b.set_label(_('and'))
+ b.set_prim_name('and')
+ b.set_special_name(_('and'))
+ b.set_help(_('logical AND operator'))
+ self.tw.lc._def_prim('not', 2, lambda self, x, y: x & y)
+ b.add_prim()
+
+ b = Primitive('or2')
+ b.set_palette('numbers')
+ b.set_style('boolean-style')
+ b.set_label(_('or'))
+ b.set_prim_name('or')
+ b.set_special_name(_('or'))
+ b.set_help(_('logical OR operator'))
+ self.tw.lc._def_prim('not', 2, lambda self, x, y: x | y)
+ b.add_prim()
+
+ def _flow_palette(self):
+ b = Primitive('wait')
+ b.set_palette('flow')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('wait'))
+ b.set_prim_name('wait')
+ b.set_default(1)
+ b.set_help(_('pauses program execution a specified number of seconds'))
+ PLUGIN_DICTIONARY['wait'] = self._prim_wait
+ self.tw.lc._def_prim('wait', 1, PLUGIN_DICTIONARY['wait'], True)
+ b.add_prim()
+
+ b = Primitive('forever')
+ b.set_palette('flow')
+ b.set_style('flow-style')
+ b.set_label(_('forever'))
+ b.set_prim_name('forever')
+ b.set_default([None, 'vspace'])
+ b.set_help(_('loops forever'))
+ PLUGIN_DICTIONARY['forever'] = self._prim_forever
+ self.tw.lc._def_prim('forever', 1, PLUGIN_DICTIONARY['forever'], True)
+ b.add_prim()
+
+ b = Primitive('repeat')
+ b.set_palette('flow')
+ b.set_style('flow-style-1arg')
+ b.set_label([' ', _('repeat')])
+ b.set_prim_name('repeat')
+ b.set_default([4, None, 'vspace'])
+ b.set_special_name(_('repeat'))
+ b.set_help(_('loops specified number of times'))
+ PLUGIN_DICTIONARY['repeat'] = self._prim_repeat
+ self.tw.lc._def_prim('repeat', 2, PLUGIN_DICTIONARY['repeat'], True)
+ b.add_prim()
+
+ b = Primitive('if')
+ b.set_palette('flow')
+ b.set_style('flow-style-boolean')
+ b.set_label([' ', _('if'), _('then')])
+ b.set_prim_name('if')
+ b.set_default([None, None, 'vspace'])
+ b.set_special_name(_('if then'))
+ b.set_help(_('if-then operator that uses boolean operators from Numbers palette'))
+ PLUGIN_DICTIONARY['if'] = self._prim_if
+ self.tw.lc._def_prim('if', 2, PLUGIN_DICTIONARY['if'], True)
+ b.add_prim()
+
+ b = Primitive('ifelse')
+ b.set_palette('flow')
+ b.set_style('flow-style-else')
+ b.set_label([' ', _('if'), _('then else')])
+ b.set_prim_name('ifelse')
+ b.set_default([None, 'vspace', None, 'vspace'])
+ b.set_special_name(_('if then else'))
+ b.set_help(_('if-then-else operator that uses boolean operators from Numbers palette'))
+ PLUGIN_DICTIONARY['ifelse'] = self._prim_ifelse
+ self.tw.lc._def_prim('ifelse', 3, PLUGIN_DICTIONARY['ifelse'], True)
+ b.add_prim()
+
+ b = Primitive('hspace')
+ b.set_palette('flow')
+ b.set_style('flow-style-tail')
+ b.set_label(' ')
+ b.set_prim_name('nop')
+ b.set_special_name(_('horizontal space'))
+ b.set_help(_('jogs stack right'))
+ self.tw.lc._def_prim('nop', 0, lambda self: None)
+ b.add_prim()
+
+ b = Primitive('vspace')
+ b.set_palette('flow')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(' ')
+ b.set_prim_name('nop')
+ b.set_special_name(_('vertical space'))
+ b.set_help(_('jogs stack down'))
+ self.tw.lc._def_prim('nop', 0, lambda self: None)
+ b.add_prim()
+
+ b = Primitive('stopstack')
+ b.set_palette('flow')
+ b.set_style('basic-style-tail')
+ b.set_label(_('stop action'))
+ b.set_prim_name('stopstack')
+ b.set_help(_('stops current action'))
+ PLUGIN_DICTIONARY['stopstack'] = self._prim_stopstack
+ self.tw.lc._def_prim('stopstack', 0,
+ lambda self: PLUGIN_DICTIONARY['stopstack']())
+ b.add_prim()
+
+ def _blocks_palette(self):
+ b = Primitive('start')
+ b.set_palette('blocks')
+ b.set_style('basic-style-head')
+ b.set_label(_('start'))
+ b.set_prim_name('start')
+ b.set_help(_('connects action to toolbar run buttons'))
+ PLUGIN_DICTIONARY['start'] = self._prim_start
+ self.tw.lc._def_prim('start', 0,
+ lambda self: PLUGIN_DICTIONARY['start']())
+ b.add_prim()
+
+ b = Primitive('storeinbox1')
+ b.set_palette('blocks')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('store in box 1'))
+ b.set_prim_name('storeinbox1')
+ b.set_default(100)
+ b.set_help(_('stores numeric value in Variable 1'))
+ PLUGIN_DICTIONARY['setbox'] = self._prim_setbox
+ self.tw.lc._def_prim('storeinbox1', 1,
+ lambda self, x: PLUGIN_DICTIONARY['setbox'](
+ 'box1', None, x))
+ b.add_prim()
+
+ b = Primitive('storeinbox2')
+ b.set_palette('blocks')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('store in box 2'))
+ b.set_prim_name('storeinbox2')
+ b.set_default(100)
+ b.set_help(_('stores numeric value in Variable 2'))
+ self.tw.lc._def_prim('storeinbox2', 1,
+ lambda self, x: PLUGIN_DICTIONARY['setbox'](
+ 'box2', None, x))
+ b.add_prim()
+
+ b = Primitive('string')
+ b.set_palette('blocks')
+ b.set_style('box-style')
+ b.set_label(_('text'))
+ b.set_default(_('text'))
+ b.set_special_name('')
+ b.set_help('string value')
+ b.add_prim()
+
+ b = Primitive('box1')
+ b.set_palette('blocks')
+ b.set_style('box-style')
+ b.set_label(_('box 1'))
+ b.set_prim_name('box1')
+ b.set_help('Variable 1 (numeric value)')
+ b.set_value_block(True)
+ self.tw.lc._def_prim('box1', 0, lambda self: self.tw.lc.boxes['box1'])
+ b.add_prim()
+
+ b = Primitive('box2')
+ b.set_palette('blocks')
+ b.set_style('box-style')
+ b.set_label(_('box 2'))
+ b.set_prim_name('box2')
+ b.set_help('Variable 2 (numeric value)')
+ b.set_value_block(True)
+ self.tw.lc._def_prim('box2', 0, lambda self: self.tw.lc.boxes['box2'])
+ b.add_prim()
+
+ b = Primitive('box')
+ b.set_palette('blocks')
+ b.set_style('number-style-1strarg')
+ b.set_label(_('box'))
+ b.set_prim_name('box')
+ b.set_default(_('my box'))
+ b.set_help('named variable (numeric value)')
+ PLUGIN_DICTIONARY['box'] = self._prim_box
+ self.tw.lc._def_prim('box', 1,
+ lambda self, x: PLUGIN_DICTONARY['box'](x))
+ b.add_prim()
+
+ b = Primitive('storein')
+ b.set_palette('blocks')
+ b.set_style('basic-style-2arg')
+ b.set_label([_('store in'), _('box'), _('value')])
+ b.set_prim_name('storeinbox')
+ b.set_default([_('my box'), 100])
+ b.set_help(_('stores numeric value in named variable'))
+ self.tw.lc._def_prim('storeinbox', 2,
+ lambda self, x, y: PLUGIN_DICTIONARY['setbox'](
+ 'box3', x, y))
+ b.add_prim()
+
+ b = Primitive('hat')
+ b.set_palette('blocks')
+ b.set_style('basic-style-head-1arg')
+ b.set_label(_('action'))
+ b.set_prim_name('nop3')
+ b.set_default(_('action'))
+ b.set_help(_('top of nameable action stack'))
+ self.tw.lc._def_prim('nop3', 1, lambda self, x: None)
+ b.add_prim()
+
+ b = Primitive('hat1')
+ b.set_palette('blocks')
+ b.set_style('basic-style-head')
+ b.set_label(_('action 1'))
+ b.set_prim_name('nop1')
+ b.set_default(_('action 1'))
+ b.set_help(_('top of Action 1 stack'))
+ self.tw.lc._def_prim('nop1', 0, lambda self: None)
+ b.add_prim()
+
+ b = Primitive('hat2')
+ b.set_palette('blocks')
+ b.set_style('basic-style-head')
+ b.set_label(_('action 2'))
+ b.set_prim_name('nop2')
+ b.set_default(_('action 2'))
+ b.set_help(_('top of Action 2 stack'))
+ self.tw.lc._def_prim('nop2', 0, lambda self: None)
+ b.add_prim()
+
+ b = Primitive('stack')
+ b.set_palette('blocks')
+ b.set_style('basic-style-1arg')
+ b.set_label(_('action'))
+ b.set_prim_name('stack')
+ b.set_default(_('action'))
+ b.set_help(_('invokes named action stack'))
+ PLUGIN_DICTIONARY['stack'] = self._prim_stack
+ self.tw.lc._def_prim('stack', 1, PLUGIN_DICTIONARY['stack'], True)
+ b.add_prim()
+
+ b = Primitive('stack1')
+ b.set_palette('blocks')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('action 1'))
+ b.set_prim_name('stack1')
+ b.set_default(_('action 1'))
+ b.set_help(_('invokes Action 1 stack'))
+ PLUGIN_DICTIONARY['stack1'] = self._prim_stack1
+ self.tw.lc._def_prim('stack1', 0, PLUGIN_DICTIONARY['stack1'], True)
+ b.add_prim()
+
+ b = Primitive('stack2')
+ b.set_palette('blocks')
+ b.set_style('basic-style-extended-vertical')
+ b.set_label(_('action 2'))
+ b.set_prim_name('stack2')
+ b.set_default(_('action 2'))
+ b.set_help(_('invokes Action 2 stack'))
+ PLUGIN_DICTIONARY['stack2'] = self._prim_stack2
+ self.tw.lc._def_prim('stack2', 0, PLUGIN_DICTIONARY['stack2'], True)
+ b.add_prim()
+
+ def _trash_palette(self):
+ b = Primitive('empty')
+ b.set_palette('trash')
+ b.set_style('basic-style-tail')
+ b.set_label(_('empty trash'))
+ b.set_help(_("permanently deletes items in trash"))
+ b.add_prim()
+
+ b = Primitive('restoreall')
+ b.set_palette('trash')
+ b.set_style('basic-style-head')
+ b.set_label(_('restore all'))
+ b.set_help(_("restore all blocks from trash"))
+ b.add_prim()
+
+ # Block primitives
+
+ def _prim_arc(self, cmd, value1, value2):
+ """ Turtle draws an arc of degree, radius """
+ cmd(float(value1), float(value2))
+ self.tw.lc.update_label_value(
+ 'xcor', self.tw.canvas.xcor / self.tw.coord_scale)
+ self.tw.lc.update_label_value(
+ 'ycor', self.tw.canvas.ycor / self.tw.coord_scale)
+ self.tw.lc.update_label_value('heading', self.tw.canvas.heading)
+ if len(self.lc.tw.value_blocks['see']) > 0:
+ self.lc.tw.see()
+
+ def _prim_box(self, x):
+ """ Retrieve value from named box """
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ try:
+ return self.tw.lc.boxes['box3' + str(x)]
+ except KeyError:
+ raise logoerror("#emptybox")
+
+ def _prim_clear(self):
+ """ Clear screen """
+ if self.tw.gst_available:
+ from tagplay import stop_media
+ # stop_media(self) # TODO: gplay variable
+ self.tw.canvas.clearscreen()
+ self.tw.lc.scale = DEFAULT_SCALE # TODO: move to lc method
+ self.tw.lc.hidden_turtle = None
+ self.tw.lc._start_time = time()
+ for name in VALUE_BLOCKS:
+ self.tw.lc.update_label_value(name)
+
+ def _prim_forever(self, blklist):
+ """ Do list forever """
+ while True:
+ self.tw.lc._icall(self.tw.lc._evline, blklist[:])
+ yield True
+ if self.tw.lc.procstop:
+ break
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_if(self, boolean, blklist):
+ """ If bool, do list """
+ if boolean:
+ self.tw.lc._icall(self.tw.lc._evline, blklist[:])
+ yield True
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_ifelse(self, boolean, list1, list2):
+ """ If bool, do list1, else do list2 """
+ if boolean:
+ self.tw.lc._ijmp(self.tw.lc._evline, list1[:])
+ yield True
+ else:
+ self.tw.lc._ijmp(self.tw.lc._evline, list2[:])
+ yield True
+
+ def _prim_move(self, cmd, value1, value2=None, pendown=True):
+ """ Turtle moves by method specified in value1 """
+ if value2 is None:
+ cmd(value1)
+ else:
+ cmd(float(value1), float(value2), pendown=pendown)
+ self.tw.lc.update_label_value('xcor',
+ self.tw.canvas.xcor / self.tw.coord_scale)
+ self.tw.lc.update_label_value('ycor',
+ self.tw.canvas.ycor / self.tw.coord_scale)
+ if len(self.tw.lc.value_blocks['see']) > 0:
+ self.tw.lc.see()
+
+ def _prim_repeat(self, num, blklist):
+ """ Repeat list num times. """
+ num = self.tw.lc._int(num)
+ for i in range(num):
+ self.tw.lc._icall(self.tw.lc._evline, blklist[:])
+ yield True
+ if self.tw.lc.procstop:
+ break
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_right(self, value):
+ """ Turtle rotates clockwise """
+ self.tw.canvas.right(float(value))
+ self.tw.lc.update_label_value('heading', self.tw.canvas.heading)
+
+ def _prim_set(self, name, cmd, value=None):
+ """ Set a value and update the associated value blocks """
+ if value is not None:
+ cmd(value)
+ self.tw.lc.update_label_value(name, value)
+
+ def _prim_setbox(self, name, x, val):
+ """ Define value of named box """
+ if x is not None:
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ self.tw.lc.boxes[name + str(x)] = val
+ return
+
+ self.tw.lc.boxes[name] = val
+ self.tw.lc.update_label_value(name, val)
+
+ def _prim_stack(self, x):
+ """ Process a named stack """
+ if type(convert(x, float, False)) == float:
+ if int(float(x)) == x:
+ x = int(x)
+ if 'stack3' + str(x) not in self.tw.lc.stacks or \
+ self.tw.lc.stacks['stack3' + str(x)] is None:
+ raise logoerror("#nostack")
+ self.tw.lc._icall(self.tw.lc._evline,
+ self.tw.lc.stacks['stack3' + str(x)][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_stack1(self):
+ """ Process Stack 1 """
+ if self.tw.lc.stacks['stack1'] is None:
+ raise logoerror("#nostack")
+ self.tw.lc._icall(self.tw.lc._evline,
+ self.tw.lc.stacks['stack1'][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_stack2(self):
+ """ Process Stack 2 """
+ if self.tw.lc.stacks['stack2'] is None:
+ raise logoerror("#nostack")
+ self.tw.lc._icall(self.tw.lc._evline, self.tw.lc.stacks['stack2'][:])
+ yield True
+ self.tw.lc.procstop = False
+ self.tw.lc._ireturn()
+ yield True
+
+ def _prim_start(self):
+ """ Start block: recenter """
+ if self.tw.running_sugar:
+ self.tw.activity.recenter()
+
+ def _prim_stopstack(self):
+ """ Stop execution of a stack """
+ self.tw.lc.procstop = True
+
+ def _prim_wait(self, time):
+ """ Show the turtle while we wait """
+ self.tw.active_turtle.show()
+ endtime = _millisecond() + time * 1000.
+ while _millisecond() < endtime:
+ yield True
+ self.tw.active_turtle.hide()
+ self.tw.lc._ireturn()
+ yield True
+
+ # Math primitivies
+
+ def _prim_careful_divide(self, x, y):
+ """ Raise error on divide by zero """
+ try:
+ return x / y
+ except ZeroDivisionError:
+ raise logoerror("#zerodivide")
+ except TypeError:
+ try:
+ return self._string_to_num(x) / self._string_to_num(y)
+ except ZeroDivisionError:
+ raise logoerror("#zerodivide")
+ except ValueError:
+ raise logoerror("#syntaxerror")
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_equal(self, x, y):
+ """ Numeric and logical equal """
+ try:
+ return float(x) == float(y)
+ except TypeError:
+ typex, typey = False, False
+ if strtype(x):
+ typex = True
+ if strtype(y):
+ typey = True
+ if typex and typey:
+ return x == y
+ try:
+ return self._string_to_num(x) == self._string_to_num(y)
+ except ValueError:
+ raise logoerror("#syntaxerror")
+
+ def _prim_less(self, x, y):
+ """ Compare numbers and strings """
+ try:
+ return float(x) < float(y)
+ except ValueError:
+ typex, typey = False, False
+ if strtype(x):
+ typex = True
+ if strtype(y):
+ typey = True
+ if typex and typey:
+ return x < y
+ try:
+ return self._string_to_num(x) < self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_more(self, x, y):
+ """ Compare numbers and strings """
+ return self._prim_less(y, x)
+
+ def _prim_plus(self, x, y):
+ """ Add numbers, concat strings """
+ if _num_type(x) and _num_type(y):
+ return(x + y)
+ else:
+ if _num_type(x):
+ xx = str(round_int(x))
+ else:
+ xx = str(x)
+ if _num_type(y):
+ yy = str(round_int(y))
+ else:
+ yy = str(y)
+ return(xx + yy)
+
+ def _prim_minus(self, x, y):
+ """ Numerical subtraction """
+ if _num_type(x) and _num_type(y):
+ return(x - y)
+ try:
+ return self._string_to_num(x) - self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_product(self, x, y):
+ """ Numerical multiplication """
+ if _num_type(x) and _num_type(y):
+ return(x * y)
+ try:
+ return self._string_to_num(x) * self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_mod(self, x, y):
+ """ Numerical mod """
+ if _num_type(x) and _num_type(y):
+ return(x % y)
+ try:
+ return self._string_to_num(x) % self._string_to_num(y)
+ except TypeError:
+ raise logoerror("#notanumber")
+ except ValueError:
+ raise logoerror("#syntaxerror")
+
+ def _prim_sqrt(self, x):
+ """ Square root """
+ if _num_type(x):
+ if x < 0:
+ raise logoerror("#negroot")
+ return sqrt(x)
+ try:
+ return sqrt(self._string_to_num(x))
+ except ValueError:
+ raise logoerror("#negroot")
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_random(self, x, y):
+ """ Random integer """
+ if _num_type(x) and _num_type(y):
+ return(int(round(uniform(x, y), 0)))
+ xx, xflag = chr_to_ord(x)
+ yy, yflag = chr_to_ord(y)
+ if xflag and yflag:
+ return chr(int(round(uniform(xx, yy), 0)))
+ if not xflag:
+ xx = self._string_to_num(x)
+ if not yflag:
+ yy = self._string_to_num(y)
+ try:
+ return(int(round(uniform(xx, yy), 0)))
+ except TypeError:
+ raise logoerror("#notanumber")
+
+ def _prim_identity(self, x):
+ """ Identity function """
+ return(x)
+
+ # Utilities
+
+ def _string_to_num(self, x):
+ """ Try to comvert a string to a number """
+ if type(x) is float:
+ return(x)
+ if type(x) is int:
+ return(x)
+ if type(x) is ord:
+ return(int(x))
+ xx = convert(x.replace(self.tw.decimal_point, '.'), float)
+ if type(xx) is float:
+ return xx
+ else:
+ xx, xflag = chr_to_ord(x)
+ if xflag:
+ return xx
+ else:
+ raise logoerror("#syntaxerror")
+
+ def _make_constant(self, block_name, palette_name, constant):
+ """ Factory for constant blocks """
+ b = Primitive(block_name)
+ b.set_palette(palette_name)
+ b.set_style('box-style')
+ b.set_label(_(block_name))
+ b.set_prim_name(block_name)
+ self.tw.lc._def_prim(block_name, 0, lambda self: constant)
+ b.add_prim()