Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/tabasics.py
diff options
context:
space:
mode:
Diffstat (limited to 'TurtleArt/tabasics.py')
-rw-r--r--TurtleArt/tabasics.py1053
1 files changed, 417 insertions, 636 deletions
diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py
index 3d1eb10..3d88ce4 100644
--- a/TurtleArt/tabasics.py
+++ b/TurtleArt/tabasics.py
@@ -20,72 +20,94 @@
#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!!)
+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
+../plugins/turtle_blocks_extras/turtle_blocks_extras.py ,
+which contains additional blocks. (Even better, write your own
+plugin!!)
Adding a new palette is simply a matter of:
+
palette = make_palette('mypalette', # the name of your palette
colors=["#00FF00", "#00A000"],
help_string=_('Palette of my custom commands'))
-For example, if we want to add a new turtle command, 'uturn', we'd use the
-add_block method in the Palette class.
+For example, if we want to add a new turtle command, 'uturn',
+we'd use the `add_block` method in the Palette class.
+
palette.add_block('uturn', # the name of your block
style='basic-style', # the block style
label=_('u turn'), # the label for the block
prim_name='uturn', # code reference (see below)
help_string=_('turns the turtle 180 degrees'))
- # Next, you need to define what your block will do:
- # def_prim takes 3 arguments: the primitive name, the number of
- # arguments -- 0 in this case -- and the function to call -- in this
- # case, we define the _prim_uturn function to set heading += 180.
- self.tw.lc.def_prim('uturn', 0, lambda self: self._prim_uturn)
- def _prim_uturn(self):
- value = self.tw.turtles.get_active_turtle().get_heading() + 180
- self.tw.turtles.get_active_turtle().set_heading(value)
+Next, you need to define what your block will do: def_prim takes
+3 arguments: the primitive name, the number of arguments --- 0
+in this case --- and a Primitive object. A Primitive object
+represents the statement to be executed when the block is
+executed in Turtle Art. For the 'uturn' block, we would like the
+statement to look roughly like this:
+
+ Turtle.set_heading(plus(Turtle.get_heading(), 180))
+
+Formally, a Primitive object consists of a function, its return
+type, and descriptions of its arguments and keyword arguments.
+The return type is not a Python type, but a type from Turtle
+Art's internal type system. All available types are defined as
+constants in tatype.py .
+
+In this case, we know in advance which arguments each function
+gets, so we can use ConstantArg objects as argument descrip-
+tions. (For examples where the arguments come from other blocks,
+please refer to ../doc/primitives-with-arguments.md .) Note that
+Primitive objects can be arguments to other Primitive objects.
+This leads to the following tree-like structure for our 'uturn'
+block:
+
+ prim_uturn = Primitive(Turtle.set_heading,
+ arg_descs=[ConstantArg(Primitive(
+ Primitive.plus, return_type=TYPE_NUMBER,
+ arg_descs=[ConstantArg(Primitive(
+ Turtle.get_heading, return_type=TYPE_NUMBER)),
+ ConstantArg(180)]))],
+ call_afterwards=self.after_uturn)
+
+ self.tw.lc.def_prim('uturn', 0, prim_uturn)
+
+ # somewhere else in the same class:
+ def after_uturn(self, value):
if self.tw.lc.update_values:
self.tw.lc.update_label_value('heading', value)
-That's it. When you next run Turtle Art, you will have a 'uturn' block
-on the 'mypalette' palette.
+The `call_afterwards` attribute is a simple function that is
+called just after executing the block. It is often used for
+updating GUI labels.
-You will have to create icons for the palette-selector buttons. These
-are kept in the icons subdirectory. You need two icons:
-mypaletteoff.svg and mypaletteon.svg, where 'mypalette' is the same
-string as the entry you used in instantiating the Palette class. Note
-that the icons should be the same size (55x55) as the others. (This is
-the default icon size for Sugar toolbars.)
-'''
+That's it. When you next run Turtle Art, you will have a 'uturn'
+block on the 'mypalette' palette.
-from time import time, sleep
-from math import sqrt
-from random import uniform
+You will have to create icons for the palette-selector buttons.
+These are kept in the 'icons' subdirectory. You need two icons:
+mypaletteoff.svg and mypaletteon.svg, where 'mypalette' is the
+same string as the entry you used in instantiating the Palette
+object. 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 gettext import gettext as _
from tapalette import (make_palette, define_logo_function)
-from talogo import (primitive_dictionary, logoerror)
-from tautils import (convert, chr_to_ord, round_int, strtype, debug_output)
-from taconstants import (COLORDICT, CONSTANTS)
-
-
-def _color_to_num(c):
- if COLORDICT[c][0] is None:
- return(COLORDICT[c][1])
- else:
- return(COLORDICT[c][0])
-
-
-def _num_type(x):
- ''' Is x a number type? '''
- if isinstance(x, (int, float)):
- return True
- return False
+from talogo import primitive_dictionary
+from taconstants import (Color, CONSTANTS)
+from taprimitive import (ArgSlot, ConstantArg, or_, Primitive)
+from tatype import (TYPE_BOOL, TYPE_BOX, TYPE_CHAR, TYPE_COLOR, TYPE_FLOAT,
+ TYPE_INT, TYPE_NUMBER, TYPE_NUMERIC_STRING, TYPE_OBJECT,
+ TYPE_STRING)
+from taturtle import Turtle
def _millisecond():
@@ -99,6 +121,15 @@ class Palettes():
def __init__(self, turtle_window):
self.tw = turtle_window
+ self.prim_cache = {
+ "minus": Primitive(Primitive.minus,
+ return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER)]),
+ "ord": Primitive(ord,
+ return_type=TYPE_INT,
+ arg_descs=[ArgSlot(TYPE_CHAR)])
+ } # avoid several Primitives of the same function
+
self._turtle_palette()
self._pen_palette()
@@ -119,13 +150,11 @@ class Palettes():
def _turtle_palette(self):
''' The basic Turtle Art turtle palette '''
- debug_output('creating %s palette' % _('turtle'),
- self.tw.running_sugar)
palette = make_palette('turtle',
colors=["#00FF00", "#00A000"],
- help_string=_('Palette of turtle commands'))
+ help_string=_('Palette of turtle commands'),
+ translation=_('turtle'))
- primitive_dictionary['move'] = self._prim_move
palette.add_block('forward',
style='basic-style-1arg',
label=_('forward'),
@@ -134,10 +163,10 @@ class Palettes():
logo_command='forward',
help_string=_('moves turtle forward'))
self.tw.lc.def_prim(
- 'forward',
- 1,
- lambda self, x: primitive_dictionary['move'](
- self.tw.turtles.get_active_turtle().forward, x))
+ 'forward', 1,
+ Primitive(Turtle.forward,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_move))
palette.add_block('back',
style='basic-style-1arg',
@@ -146,13 +175,12 @@ class Palettes():
default=100,
logo_command='back',
help_string=_('moves turtle backward'))
- self.tw.lc.def_prim('back', 1,
- lambda self, x:
- primitive_dictionary['move']
- (self.tw.turtles.get_active_turtle().forward, x,
- reverse=True))
+ self.tw.lc.def_prim(
+ 'back', 1,
+ Primitive(Turtle.backward,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_move))
- primitive_dictionary['clean'] = self._prim_clear
palette.add_block('clean',
style='basic-style-extended-vertical',
label=_('clean'),
@@ -160,12 +188,19 @@ class Palettes():
logo_command='clean',
help_string=_('clears the screen and reset the \
turtle'))
- self.tw.lc.def_prim(
- 'clean',
- 0,
- lambda self: primitive_dictionary['clean']())
+ self.tw.lc.def_prim('clean', 0,
+ Primitive(Primitive.group, arg_descs=[
+ ConstantArg([
+ Primitive(self.tw.clear_plugins),
+ Primitive(self.tw.lc.stop_playing_media),
+ Primitive(self.tw.lc.reset_scale),
+ Primitive(self.tw.lc.reset_timer),
+ Primitive(self.tw.lc.clear_value_blocks),
+ Primitive(self.tw.lc.reset_internals),
+ Primitive(self.tw.canvas.clearscreen),
+ Primitive(self.tw.turtles.reset_turtles)
+ ])]))
- primitive_dictionary['right'] = self._prim_right
palette.add_block('left',
style='basic-style-1arg',
label=_('left'),
@@ -175,8 +210,10 @@ turtle'))
help_string=_('turns turtle counterclockwise (angle \
in degrees)'))
self.tw.lc.def_prim(
- 'left', 1, lambda self,
- x: primitive_dictionary['right'](x, reverse=True))
+ 'left', 1,
+ Primitive(Turtle.left,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_right))
palette.add_block('right',
style='basic-style-1arg',
@@ -187,11 +224,11 @@ in degrees)'))
help_string=_('turns turtle clockwise (angle in \
degrees)'))
self.tw.lc.def_prim(
- 'right',
- 1,
- lambda self, x: primitive_dictionary['right'](x))
+ 'right', 1,
+ Primitive(Turtle.right,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_right))
- primitive_dictionary['arc'] = self._prim_arc
palette.add_block('arc',
style='basic-style-2arg',
label=[_('arc'), _('angle'), _('radius')],
@@ -200,10 +237,11 @@ degrees)'))
logo_command='taarc',
help_string=_('moves turtle along an arc'))
self.tw.lc.def_prim(
- 'arc',
- 2,
- lambda self, x, y: primitive_dictionary['arc'](
- self.tw.turtles.get_active_turtle().arc, x, y))
+ 'arc', 2,
+ Primitive(Turtle.arc,
+ arg_descs=[ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_arc))
define_logo_function('taarc', 'to taarc :a :r\nrepeat round :a \
[right 1 forward (0.0175 * :r)]\nend\n')
@@ -216,13 +254,12 @@ degrees)'))
help_string=_('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: primitive_dictionary['move'](
- self.tw.turtles.get_active_turtle().set_xy, x, y))
+ 'setxy2', 2,
+ Primitive(Turtle.set_xy,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)],
+ call_afterwards=self.after_move))
define_logo_function('tasetxy', 'to tasetxy :x :y\nsetxy :x :y\nend\n')
- primitive_dictionary['set'] = self._prim_set
palette.add_block('seth',
style='basic-style-1arg',
label=_('set heading'),
@@ -232,10 +269,11 @@ degrees)'))
help_string=_('sets the heading of the turtle (0 is \
towards the top of the screen.)'))
self.tw.lc.def_prim(
- 'seth',
- 1,
- lambda self, x: primitive_dictionary['set'](
- 'heading', self.tw.turtles.get_active_turtle().set_heading, x))
+ 'seth', 1,
+ Primitive(Turtle.set_heading,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=lambda value: self.after_set(
+ 'heading', value)))
palette.add_block('xcor',
style='box-style',
@@ -246,10 +284,11 @@ the turtle (can be used in place of a number block)'),
prim_name='xcor',
logo_command='xcor')
self.tw.lc.def_prim(
- 'xcor',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_xy()[0] /
- self.tw.coord_scale)
+ 'xcor', 0,
+ Primitive(Primitive.divide, return_type=TYPE_FLOAT,
+ arg_descs=[ConstantArg(Primitive(Turtle.get_x)),
+ ConstantArg(Primitive(
+ self.tw.get_coord_scale))]))
palette.add_block('ycor',
style='box-style',
@@ -260,10 +299,11 @@ the turtle (can be used in place of a number block)'),
prim_name='ycor',
logo_command='ycor')
self.tw.lc.def_prim(
- 'ycor',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_xy()[1] /
- self.tw.coord_scale)
+ 'ycor', 0,
+ Primitive(Primitive.divide, return_type=TYPE_FLOAT,
+ arg_descs=[ConstantArg(Primitive(Turtle.get_y)),
+ ConstantArg(Primitive(
+ self.tw.get_coord_scale))]))
palette.add_block('heading',
style='box-style',
@@ -273,16 +313,14 @@ turtle (can be used in place of a number block)'),
value_block=True,
prim_name='heading',
logo_command='heading')
- self.tw.lc.def_prim(
- 'heading',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_heading())
+ self.tw.lc.def_prim('heading', 0,
+ Primitive(
+ Turtle.get_heading, return_type=TYPE_NUMBER))
- # This block is used for holding the remote turtle name
palette.add_block('turtle-label',
hidden=True,
style='blank-style',
- label=['remote turtle name'])
+ label=['turtle'])
# Deprecated
palette.add_block('setxy',
@@ -295,22 +333,21 @@ turtle (can be used in place of a number block)'),
help_string=_('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: primitive_dictionary['move'](
- self.tw.turtles.get_active_turtle().set_xy, x, y,
- pendown=False))
+ 'setxy', 2,
+ Primitive(Turtle.set_xy,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)],
+ kwarg_descs={'pendown': ConstantArg(False)},
+ call_afterwards=self.after_move))
define_logo_function('tasetxypenup', 'to tasetxypenup :x :y\npenup\n\
setxy :x :y\npendown\nend\n')
def _pen_palette(self):
''' The basic Turtle Art pen palette '''
- debug_output('creating %s palette' % _('pen'),
- self.tw.running_sugar)
palette = make_palette('pen',
colors=["#00FFFF", "#00A0A0"],
- help_string=_('Palette of pen commands'))
+ help_string=_('Palette of pen commands'),
+ translation=_('pen'))
palette.add_block('fillscreen',
hidden=True,
@@ -322,9 +359,9 @@ setxy :x :y\npendown\nend\n')
help_string=_('fills the background with (color, \
shade)'))
self.tw.lc.def_prim(
- 'fillscreen',
- 2,
- lambda self, x, y: self.tw.canvas.fillscreen(x, y))
+ 'fillscreen', 2,
+ Primitive(self.tw.canvas.fillscreen,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)]))
palette.add_block('fillscreen2',
style='basic-style-3arg',
@@ -336,9 +373,10 @@ shade)'))
help_string=_('fills the background with (color, \
shade)'))
self.tw.lc.def_prim(
- 'fillscreen2',
- 3,
- lambda self, x, y, z: self.tw.canvas.fillscreen_with_gray(x, y, z))
+ 'fillscreen2', 3,
+ Primitive(self.tw.canvas.fillscreen_with_gray,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)]))
define_logo_function('tasetbackground', 'to tasetbackground :color \
:shade\ntasetshade :shade\nsetbackground :color\nend\n')
@@ -352,10 +390,12 @@ shade)'))
help_string=_('sets color of the line drawn by the \
turtle'))
self.tw.lc.def_prim(
- 'setcolor',
- 1,
- lambda self, x: primitive_dictionary['set'](
- 'color', self.tw.turtles.get_active_turtle().set_color, x))
+ 'setcolor', 1,
+ Primitive(Turtle.set_color,
+ arg_descs=[or_(ArgSlot(TYPE_COLOR),
+ ArgSlot(TYPE_NUMBER))],
+ call_afterwards=lambda value: self.after_set(
+ 'color', value)))
palette.add_block('setshade',
style='basic-style-1arg',
@@ -366,10 +406,11 @@ turtle'))
help_string=_('sets shade of the line drawn by the \
turtle'))
self.tw.lc.def_prim(
- 'setshade',
- 1,
- lambda self, x: primitive_dictionary['set'](
- 'shade', self.tw.turtles.get_active_turtle().set_shade, x))
+ 'setshade', 1,
+ Primitive(Turtle.set_shade,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=lambda value: self.after_set(
+ 'shade', value)))
palette.add_block('setgray',
style='basic-style-1arg',
@@ -379,10 +420,11 @@ turtle'))
help_string=_('sets gray level of the line drawn by \
the turtle'))
self.tw.lc.def_prim(
- 'setgray',
- 1,
- lambda self, x: primitive_dictionary['set'](
- 'gray', self.tw.turtles.get_active_turtle().set_gray, x))
+ 'setgray', 1,
+ Primitive(Turtle.set_gray,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=lambda value: self.after_set(
+ 'gray', value)))
palette.add_block('color',
style='box-style',
@@ -392,10 +434,9 @@ in place of a number block)'),
value_block=True,
prim_name='color',
logo_command='pencolor')
- self.tw.lc.def_prim(
- 'color',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_color())
+ self.tw.lc.def_prim('color', 0,
+ Primitive(
+ Turtle.get_color, return_type=TYPE_NUMBER))
palette.add_block('shade',
style='box-style',
@@ -404,10 +445,7 @@ in place of a number block)'),
value_block=True,
prim_name='shade',
logo_command=':shade')
- self.tw.lc.def_prim(
- 'shade',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_shade())
+ self.tw.lc.def_prim('shade', 0, Primitive(Turtle.get_shade))
palette.add_block('gray',
style='box-style',
@@ -416,8 +454,9 @@ in place of a number block)'),
used in place of a number block)'),
value_block=True,
prim_name='gray')
- self.tw.lc.def_prim('gray', 0, lambda self:
- self.tw.turtles.get_active_turtle().get_gray())
+ self.tw.lc.def_prim('gray', 0,
+ Primitive(
+ Turtle.get_gray, return_type=TYPE_NUMBER))
palette.add_block('penup',
style='basic-style-extended-vertical',
@@ -426,10 +465,8 @@ used in place of a number block)'),
logo_command='penup',
help_string=_('Turtle will not draw when moved.'))
self.tw.lc.def_prim(
- 'penup',
- 0,
- lambda self:
- self.tw.turtles.get_active_turtle().set_pen_state(False))
+ 'penup', 0,
+ Primitive(Turtle.set_pen_state, arg_descs=[ConstantArg(False)]))
palette.add_block('pendown',
style='basic-style-extended-vertical',
@@ -438,10 +475,8 @@ used in place of a number block)'),
logo_command='pendown',
help_string=_('Turtle will draw when moved.'))
self.tw.lc.def_prim(
- 'pendown',
- 0,
- lambda self:
- self.tw.turtles.get_active_turtle().set_pen_state(True))
+ 'pendown', 0,
+ Primitive(Turtle.set_pen_state, arg_descs=[ConstantArg(True)]))
palette.add_block('penstate',
style='boolean-block-style',
@@ -449,9 +484,8 @@ used in place of a number block)'),
prim_name='penstate',
help_string=_('returns True if pen is down'))
self.tw.lc.def_prim(
- 'penstate',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_pen_state())
+ 'penstate', 0,
+ Primitive(Turtle.get_pen_state, return_type=TYPE_BOOL))
palette.add_block('setpensize',
style='basic-style-1arg',
@@ -463,8 +497,10 @@ used in place of a number block)'),
turtle'))
self.tw.lc.def_prim(
'setpensize', 1,
- lambda self, x: primitive_dictionary['set']
- ('pensize', self.tw.turtles.get_active_turtle().set_pen_size, x))
+ Primitive(Turtle.set_pen_size,
+ arg_descs=[ArgSlot(TYPE_NUMBER)],
+ call_afterwards=lambda val: self.after_set(
+ 'pensize', val)))
define_logo_function('tasetpensize',
'to tasetpensize :a\nsetpensize round :a\nend\n')
@@ -474,10 +510,7 @@ turtle'))
prim_name='startfill',
help_string=_('starts filled polygon (used with end \
fill block)'))
- self.tw.lc.def_prim(
- 'startfill',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().start_fill())
+ self.tw.lc.def_prim('startfill', 0, Primitive(Turtle.start_fill))
palette.add_block('stopfill',
style='basic-style-extended-vertical',
@@ -485,10 +518,7 @@ fill block)'))
prim_name='stopfill',
help_string=_('completes filled polygon (used with \
start fill block)'))
- self.tw.lc.def_prim(
- 'stopfill',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().stop_fill())
+ self.tw.lc.def_prim('stopfill', 0, Primitive(Turtle.stop_fill))
palette.add_block('pensize',
style='box-style',
@@ -499,33 +529,27 @@ in place of a number block)'),
prim_name='pensize',
logo_command='pensize')
self.tw.lc.def_prim(
- 'pensize',
- 0,
- lambda self: self.tw.turtles.get_active_turtle().get_pen_size())
+ 'pensize', 0,
+ Primitive(Turtle.get_pen_size, return_type=TYPE_NUMBER))
define_logo_function('tapensize', 'to tapensize\noutput first round \
pensize\nend\n')
def _color_palette(self):
''' The basic Turtle Art color palette '''
- debug_output('creating %s palette' % _('colors'),
- self.tw.running_sugar)
palette = make_palette('colors',
colors=["#00FFFF", "#00A0A0"],
- help_string=_('Palette of pen colors'))
-
- self._make_constant(palette, 'red', _('red'), CONSTANTS['red'])
- self._make_constant(palette, 'orange', _('orange'),
- CONSTANTS['orange'])
- self._make_constant(palette, 'yellow', _('yellow'),
- CONSTANTS['yellow'])
- self._make_constant(palette, 'green', _('green'), CONSTANTS['green'])
- self._make_constant(palette, 'cyan', _('cyan'), CONSTANTS['cyan'])
- self._make_constant(palette, 'blue', _('blue'), CONSTANTS['blue'])
- self._make_constant(palette, 'purple', _('purple'),
- CONSTANTS['purple'])
- self._make_constant(palette, 'white', _('white'), CONSTANTS['white'])
- self._make_constant(palette, 'black', _('black'), CONSTANTS['black'])
+ help_string=_('Palette of pen colors'),
+ translation=_('colors'))
+
+ color_names = ('red', 'orange', 'yellow', 'green', 'cyan', 'blue',
+ 'purple', 'white', 'black')
+ # Need to make sure color names are included in the PO files
+ color_names_i18n = (_('red'), _('orange'), _('yellow'), _('green'),
+ _('cyan'), _('blue'), _('purple'), _('white'),
+ _('black'))
+ for name in color_names:
+ self._make_constant(palette, name, _(name), name)
# In order to map Turtle Art colors to the standard UCB Logo palette,
# we need to define a somewhat complex set of functions.
@@ -603,13 +627,11 @@ tasetshade :shade \n')
def _numbers_palette(self):
''' The basic Turtle Art numbers palette '''
- debug_output('creating %s palette' % _('numbers'),
- self.tw.running_sugar)
palette = make_palette('numbers',
colors=["#FF00FF", "#A000A0"],
- help_string=_('Palette of numeric operators'))
+ help_string=_('Palette of numeric operators'),
+ translation=_('numbers'))
- primitive_dictionary['plus'] = self._prim_plus
palette.add_block('plus2',
style='number-style',
label='+',
@@ -619,9 +641,16 @@ tasetshade :shade \n')
logo_command='sum',
help_string=_('adds two alphanumeric inputs'))
self.tw.lc.def_prim(
- 'plus', 2, lambda self, x, y: primitive_dictionary['plus'](x, y))
+ 'plus', 2,
+ # add up two numbers ...
+ or_(Primitive(Primitive.plus, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)]),
+ # ... or concatenate two strings
+ Primitive(Primitive.plus, return_type=TYPE_STRING,
+ arg_descs=[ArgSlot(TYPE_STRING),
+ ArgSlot(TYPE_STRING)])))
- primitive_dictionary['minus'] = self._prim_minus
palette.add_block('minus2',
style='number-style-porch',
label=' –',
@@ -631,11 +660,12 @@ tasetshade :shade \n')
help_string=_('subtracts bottom numeric input from \
top numeric input'))
self.tw.lc.def_prim(
- 'minus', 2, lambda self, x, y: primitive_dictionary['minus'](x, y))
+ 'minus', 2,
+ Primitive(Primitive.minus, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)]))
define_logo_function('taminus', 'to taminus :y :x\noutput sum :x \
minus :y\nend\n')
- primitive_dictionary['product'] = self._prim_product
palette.add_block('product2',
style='number-style',
label='×',
@@ -645,9 +675,9 @@ minus :y\nend\n')
help_string=_('multiplies two numeric inputs'))
self.tw.lc.def_prim(
'product', 2,
- lambda self, x, y: primitive_dictionary['product'](x, y))
+ Primitive(Primitive.multiply, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)]))
- primitive_dictionary['division'] = self._prim_careful_divide
palette.add_block('division2',
style='number-style-porch',
label=' /',
@@ -658,9 +688,9 @@ minus :y\nend\n')
(numerator) by bottom numeric input (denominator)'))
self.tw.lc.def_prim(
'division', 2,
- lambda self, x, y: primitive_dictionary['division'](x, y))
+ Primitive(Primitive.divide, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)]))
- primitive_dictionary['id'] = self._prim_identity
palette.add_block('identity2',
style='number-style-1arg',
label='←',
@@ -668,10 +698,26 @@ minus :y\nend\n')
prim_name='id',
help_string=_('identity operator used for extending \
blocks'))
- self.tw.lc.def_prim('id', 1,
- lambda self, x: primitive_dictionary['id'](x))
+ self.tw.lc.def_prim(
+ 'id', 1,
+ # preserve the Type of the argument: try less general types first
+ or_(Primitive(Primitive.identity, return_type=TYPE_NUMERIC_STRING,
+ arg_descs=[ArgSlot(TYPE_NUMERIC_STRING)]),
+ Primitive(Primitive.identity, return_type=TYPE_CHAR,
+ arg_descs=[ArgSlot(TYPE_CHAR)]),
+ Primitive(Primitive.identity, return_type=TYPE_COLOR,
+ arg_descs=[ArgSlot(TYPE_COLOR)]),
+ Primitive(Primitive.identity, return_type=TYPE_FLOAT,
+ arg_descs=[ArgSlot(TYPE_FLOAT)]),
+ Primitive(Primitive.identity, return_type=TYPE_INT,
+ arg_descs=[ArgSlot(TYPE_INT)]),
+ Primitive(Primitive.identity, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER)]),
+ Primitive(Primitive.identity, return_type=TYPE_STRING,
+ arg_descs=[ArgSlot(TYPE_STRING)]),
+ Primitive(Primitive.identity, return_type=TYPE_OBJECT,
+ arg_descs=[ArgSlot(TYPE_OBJECT)])))
- primitive_dictionary['remainder'] = self._prim_mod
palette.add_block('remainder2',
style='number-style-porch',
label=_('mod'),
@@ -679,11 +725,11 @@ blocks'))
prim_name='remainder',
logo_command='remainder',
help_string=_('modular (remainder) operator'))
- self.tw.lc.def_prim('remainder', 2,
- lambda self, x, y:
- primitive_dictionary['remainder'](x, y))
+ self.tw.lc.def_prim(
+ 'remainder', 2,
+ Primitive(Primitive.modulo, return_type=TYPE_NUMBER,
+ arg_descs=[ArgSlot(TYPE_NUMBER), ArgSlot(TYPE_NUMBER)]))
- primitive_dictionary['sqrt'] = self._prim_sqrt
palette.add_block('sqrt',
style='number-style-1arg',
label=_('√'),
@@ -691,10 +737,11 @@ blocks'))
prim_name='sqrt',
logo_command='tasqrt',
help_string=_('calculates square root'))
- self.tw.lc.def_prim('sqrt', 1,
- lambda self, x: primitive_dictionary['sqrt'](x))
+ self.tw.lc.def_prim(
+ 'sqrt', 1,
+ Primitive(Primitive.square_root, return_type=TYPE_FLOAT,
+ arg_descs=[ArgSlot(TYPE_NUMBER)]))
- primitive_dictionary['random'] = self._prim_random
palette.add_block('random',
style='number-style-block',
label=[_('random'), _('min'), _('max')],
@@ -703,9 +750,19 @@ blocks'))
logo_command='tarandom',
help_string=_('returns random number between \
minimum (top) and maximum (bottom) values'))
+
self.tw.lc.def_prim(
- 'random', 2, lambda self, x, y: primitive_dictionary['random'](
- x, y))
+ 'random', 2,
+ or_( # random character ...
+ Primitive(Primitive.random_char, return_type=TYPE_CHAR,
+ arg_descs=[
+ ArgSlot(TYPE_INT,
+ wrapper=self.prim_cache["ord"]),
+ ArgSlot(TYPE_INT,
+ wrapper=self.prim_cache["ord"])]),
+ # ... or random number
+ Primitive(Primitive.random_int, return_type=TYPE_INT,
+ arg_descs=[ArgSlot(TYPE_INT), ArgSlot(TYPE_INT)])))
define_logo_function('tarandom', 'to tarandom :min :max\n \
output (random (:max - :min)) + :min\nend\n')
@@ -717,7 +774,6 @@ output (random (:max - :min)) + :min\nend\n')
help_string=_('used as numeric input in mathematic \
operators'))
- primitive_dictionary['more'] = self._prim_more
palette.add_block('greater2',
style='compare-porch-style',
label=' >',
@@ -728,9 +784,16 @@ operators'))
help_string=_('logical greater-than operator'))
self.tw.lc.def_prim(
'greater?', 2,
- lambda self, x, y: primitive_dictionary['more'](x, y))
+ Primitive(Primitive.greater, return_type=TYPE_BOOL,
+ arg_descs=or_([ArgSlot(TYPE_COLOR),
+ ArgSlot(TYPE_COLOR)],
+ [ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)],
+ [ArgSlot(TYPE_STRING),
+ ArgSlot(TYPE_STRING)],
+ [ArgSlot(TYPE_OBJECT),
+ ArgSlot(TYPE_OBJECT)])))
- primitive_dictionary['less'] = self._prim_less
palette.add_block('less2',
style='compare-porch-style',
label=' <',
@@ -740,9 +803,17 @@ operators'))
logo_command='less?',
help_string=_('logical less-than operator'))
self.tw.lc.def_prim(
- 'less?', 2, lambda self, x, y: primitive_dictionary['less'](x, y))
+ 'less?', 2,
+ Primitive(Primitive.less, return_type=TYPE_BOOL,
+ arg_descs=or_([ArgSlot(TYPE_COLOR),
+ ArgSlot(TYPE_COLOR)],
+ [ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)],
+ [ArgSlot(TYPE_STRING),
+ ArgSlot(TYPE_STRING)],
+ [ArgSlot(TYPE_OBJECT),
+ ArgSlot(TYPE_OBJECT)])))
- primitive_dictionary['equal'] = self._prim_equal
palette.add_block('equal2',
style='compare-style',
label='=',
@@ -751,9 +822,17 @@ operators'))
prim_name='equal?',
logo_command='equal?',
help_string=_('logical equal-to operator'))
- self.tw.lc.def_prim('equal?', 2,
- lambda self, x, y:
- primitive_dictionary['equal'](x, y))
+ self.tw.lc.def_prim(
+ 'equal?', 2,
+ Primitive(Primitive.equals, return_type=TYPE_BOOL,
+ arg_descs=or_([ArgSlot(TYPE_COLOR),
+ ArgSlot(TYPE_COLOR)],
+ [ArgSlot(TYPE_NUMBER),
+ ArgSlot(TYPE_NUMBER)],
+ [ArgSlot(TYPE_STRING),
+ ArgSlot(TYPE_STRING)],
+ [ArgSlot(TYPE_OBJECT),
+ ArgSlot(TYPE_OBJECT)])))
palette.add_block('not',
style='not-style',
@@ -761,9 +840,11 @@ operators'))
prim_name='not',
logo_command='not',
help_string=_('logical NOT operator'))
- self.tw.lc.def_prim('not', 1, lambda self, x: not x)
+ self.tw.lc.def_prim(
+ 'not', 1,
+ Primitive(Primitive.not_, return_type=TYPE_BOOL,
+ arg_descs=[ArgSlot(TYPE_BOOL)]))
- primitive_dictionary['and'] = self._prim_and
palette.add_block('and2',
style='boolean-style',
label=_('and'),
@@ -772,9 +853,10 @@ operators'))
special_name=_('and'),
help_string=_('logical AND operator'))
self.tw.lc.def_prim(
- 'and', 2, lambda self, x, y: primitive_dictionary['and'](x, y))
+ 'and', 2,
+ Primitive(Primitive.and_, return_type=TYPE_BOOL,
+ arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_BOOL)]))
- primitive_dictionary['or'] = self._prim_or
palette.add_block('or2',
style='boolean-style',
label=_('or'),
@@ -783,18 +865,18 @@ operators'))
special_name=_('or'),
help_string=_('logical OR operator'))
self.tw.lc.def_prim(
- 'or', 2, lambda self, x, y: primitive_dictionary['or'](x, y))
+ 'or', 2,
+ Primitive(Primitive.or_, return_type=TYPE_BOOL,
+ arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_BOOL)]))
def _flow_palette(self):
''' The basic Turtle Art flow palette '''
- debug_output('creating %s palette' % _('flow'),
- self.tw.running_sugar)
palette = make_palette('flow',
colors=["#FFC000", "#A08000"],
- help_string=_('Palette of flow operators'))
+ help_string=_('Palette of flow operators'),
+ translation=_('flow'))
- primitive_dictionary['wait'] = self._prim_wait
palette.add_block('wait',
style='basic-style-1arg',
label=_('wait'),
@@ -803,9 +885,11 @@ operators'))
logo_command='wait',
help_string=_('pauses program execution a specified \
number of seconds'))
- self.tw.lc.def_prim('wait', 1, primitive_dictionary['wait'], True)
+ self.tw.lc.def_prim(
+ 'wait', 1,
+ Primitive(self.tw.lc.prim_wait, arg_descs=[ArgSlot(TYPE_NUMBER)]),
+ True)
- primitive_dictionary['forever'] = self._prim_forever
palette.add_block('forever',
style='clamp-style',
label=_('forever'),
@@ -813,10 +897,13 @@ number of seconds'))
default=[None, None],
logo_command='forever',
help_string=_('loops forever'))
- self.tw.lc.def_prim('forever', 1, primitive_dictionary['forever'],
- True)
+ self.tw.lc.def_prim(
+ 'forever', 1,
+ Primitive(self.tw.lc.prim_loop, arg_descs=[ConstantArg(Primitive(
+ Primitive.controller_forever)), ArgSlot(TYPE_OBJECT,
+ call_arg=False)]),
+ True)
- primitive_dictionary['repeat'] = self._prim_repeat
palette.add_block('repeat',
style='clamp-style-1arg',
label=_('repeat'),
@@ -825,9 +912,16 @@ number of seconds'))
logo_command='repeat',
special_name=_('repeat'),
help_string=_('loops specified number of times'))
- self.tw.lc.def_prim('repeat', 2, primitive_dictionary['repeat'], True)
+ self.tw.lc.def_prim(
+ 'repeat', 2,
+ Primitive(self.tw.lc.prim_loop,
+ arg_descs=[ArgSlot(
+ TYPE_OBJECT,
+ wrapper=Primitive(Primitive.controller_repeat,
+ arg_descs=[ArgSlot(TYPE_INT)])),
+ ArgSlot(TYPE_OBJECT, call_arg=False)]),
+ True)
- primitive_dictionary['if'] = self._prim_if
palette.add_block('if',
style='clamp-style-boolean',
label=[_('if'), _('then'), ''],
@@ -837,9 +931,12 @@ number of seconds'))
logo_command='if',
help_string=_('if-then operator that uses boolean \
operators from Numbers palette'))
- self.tw.lc.def_prim('if', 2, primitive_dictionary['if'], True)
+ self.tw.lc.def_prim(
+ 'if', 2,
+ Primitive(self.tw.lc.prim_if,
+ arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_OBJECT)]),
+ True)
- primitive_dictionary['ifelse'] = self._prim_ifelse
palette.add_block('ifelse',
hidden=True, # Too big to fit palette
style='clamp-style-else',
@@ -850,7 +947,12 @@ operators from Numbers palette'))
special_name=_('if then else'),
help_string=_('if-then-else operator that uses \
boolean operators from Numbers palette'))
- self.tw.lc.def_prim('ifelse', 3, primitive_dictionary['ifelse'], True)
+ self.tw.lc.def_prim(
+ 'ifelse', 3,
+ Primitive(self.tw.lc.prim_ifelse,
+ arg_descs=[ArgSlot(TYPE_BOOL), ArgSlot(TYPE_OBJECT),
+ ArgSlot(TYPE_OBJECT)]),
+ True)
# macro
palette.add_block('ifthenelse',
@@ -867,7 +969,9 @@ boolean operators from Numbers palette'))
prim_name='nop',
special_name=_('horizontal space'),
help_string=_('jogs stack right'))
- self.tw.lc.def_prim('nop', 0, lambda self: None)
+ self.tw.lc.def_prim(
+ 'nop', 0,
+ Primitive(Primitive.do_nothing, export_me=False))
palette.add_block('vspace',
style='basic-style-extended-vertical',
@@ -875,28 +979,28 @@ boolean operators from Numbers palette'))
prim_name='nop',
special_name=_('vertical space'),
help_string=_('jogs stack down'))
- self.tw.lc.def_prim('nop', 0, lambda self: None)
+ self.tw.lc.def_prim(
+ 'nop', 0,
+ Primitive(Primitive.do_nothing, export_me=False))
- primitive_dictionary['stopstack'] = self._prim_stopstack
palette.add_block('stopstack',
style='basic-style-tail',
label=_('stop action'),
prim_name='stopstack',
logo_command='stop',
help_string=_('stops current action'))
- self.tw.lc.def_prim('stopstack', 0,
- lambda self: primitive_dictionary['stopstack']())
+ self.tw.lc.def_prim(
+ 'stopstack', 0,
+ Primitive(self.tw.lc.prim_stop_stack))
def _blocks_palette(self):
''' The basic Turtle Art blocks palette '''
- debug_output('creating %s palette' % _('blocks'),
- self.tw.running_sugar)
palette = make_palette('blocks',
colors=["#FFFF00", "#A0A000"],
- help_string=_('Palette of variable blocks'))
+ help_string=_('Palette of variable blocks'),
+ translation=_('blocks'))
- primitive_dictionary['start'] = self._prim_start
palette.add_block('start',
style='basic-style-head',
label=_('start'),
@@ -904,8 +1008,13 @@ boolean operators from Numbers palette'))
logo_command='to start\n',
help_string=_('connects action to toolbar run \
buttons'))
- self.tw.lc.def_prim('start', 0,
- lambda self: primitive_dictionary['start']())
+ self.tw.lc.def_prim(
+ 'start', 0,
+ Primitive(Primitive.group, arg_descs=[ConstantArg([
+ Primitive(self.tw.lc.prim_start,
+ export_me=False),
+ Primitive(self.tw.lc.prim_define_stack,
+ arg_descs=[ConstantArg('start')])])]))
palette.add_block('string',
style='box-style',
@@ -922,9 +1031,14 @@ buttons'))
default=_('action'),
logo_command='to action',
help_string=_('top of nameable action stack'))
- self.tw.lc.def_prim('nop3', 1, lambda self, x: None)
+ self.tw.lc.def_prim(
+ 'nop3', 1,
+ Primitive(self.tw.lc.prim_define_stack,
+ arg_descs=[ArgSlot(TYPE_OBJECT)]))
- primitive_dictionary['stack'] = self._prim_stack
+ primitive_dictionary['stack'] = Primitive(
+ self.tw.lc.prim_invoke_stack,
+ arg_descs=[ArgSlot(TYPE_OBJECT)])
palette.add_block('stack',
style='basic-style-1arg',
label=_('action'),
@@ -933,9 +1047,9 @@ buttons'))
logo_command='action',
default=_('action'),
help_string=_('invokes named action stack'))
- self.tw.lc.def_prim('stack', 1, primitive_dictionary['stack'], True)
+ self.tw.lc.def_prim('stack', 1,
+ primitive_dictionary['stack'], True)
- primitive_dictionary['setbox'] = self._prim_setbox
palette.add_block('storeinbox1',
hidden=True,
style='basic-style-1arg',
@@ -945,10 +1059,10 @@ buttons'))
string_or_number=True,
logo_command='make "box1',
help_string=_('stores numeric value in Variable 1'))
- self.tw.lc.def_prim('storeinbox1', 1,
- lambda self, x:
- primitive_dictionary['setbox']
- ('box1', None, x))
+ self.tw.lc.def_prim(
+ 'storeinbox1', 1,
+ Primitive(self.tw.lc.prim_set_box,
+ arg_descs=[ConstantArg('box1'), ArgSlot(TYPE_OBJECT)]))
palette.add_block('storeinbox2',
hidden=True,
@@ -959,10 +1073,10 @@ buttons'))
string_or_number=True,
logo_command='make "box2',
help_string=_('stores numeric value in Variable 2'))
- self.tw.lc.def_prim('storeinbox2', 1,
- lambda self, x:
- primitive_dictionary['setbox']
- ('box2', None, x))
+ self.tw.lc.def_prim(
+ 'storeinbox2', 1,
+ Primitive(self.tw.lc.prim_set_box,
+ arg_descs=[ConstantArg('box2'), ArgSlot(TYPE_OBJECT)]))
palette.add_block('box1',
hidden=True,
@@ -972,7 +1086,10 @@ buttons'))
logo_command=':box1',
help_string=_('Variable 1 (numeric value)'),
value_block=True)
- self.tw.lc.def_prim('box1', 0, lambda self: self.tw.lc.boxes['box1'])
+ self.tw.lc.def_prim(
+ 'box1', 0,
+ Primitive(self.tw.lc.prim_get_box, return_type=TYPE_BOX,
+ arg_descs=[ConstantArg('box1')]))
palette.add_block('box2',
hidden=True,
@@ -982,8 +1099,14 @@ buttons'))
logo_command=':box2',
help_string=_('Variable 2 (numeric value)'),
value_block=True)
- self.tw.lc.def_prim('box2', 0, lambda self: self.tw.lc.boxes['box2'])
+ self.tw.lc.def_prim(
+ 'box2', 0,
+ Primitive(self.tw.lc.prim_get_box, return_type=TYPE_BOX,
+ arg_descs=[ConstantArg('box2')]))
+ primitive_dictionary['setbox'] = Primitive(
+ self.tw.lc.prim_set_box,
+ arg_descs=[ArgSlot(TYPE_OBJECT), ArgSlot(TYPE_OBJECT)])
palette.add_block('storein',
style='basic-style-2arg',
label=[_('store in'), _('box'), _('value')],
@@ -993,12 +1116,12 @@ buttons'))
default=[_('my box'), 100],
help_string=_('stores numeric value in named \
variable'))
- self.tw.lc.def_prim('storeinbox', 2,
- lambda self, x, y:
- primitive_dictionary['setbox']
- ('box3', x, y))
+ self.tw.lc.def_prim('storeinbox', 2, primitive_dictionary['setbox'])
- primitive_dictionary['box'] = self._prim_box
+ primitive_dictionary['box'] = Primitive(
+ self.tw.lc.prim_get_box,
+ return_type=TYPE_BOX,
+ arg_descs=[ArgSlot(TYPE_OBJECT)])
palette.add_block('box',
style='number-style-1strarg',
hidden=True,
@@ -1009,8 +1132,7 @@ variable'))
logo_command='box',
value_block=True,
help_string=_('named variable (numeric value)'))
- self.tw.lc.def_prim('box', 1,
- lambda self, x: primitive_dictionary['box'](x))
+ self.tw.lc.def_prim('box', 1, primitive_dictionary['box'])
palette.add_block('hat1',
hidden=True,
@@ -1019,7 +1141,10 @@ variable'))
prim_name='nop1',
logo_command='to stack1\n',
help_string=_('top of Action 1 stack'))
- self.tw.lc.def_prim('nop1', 0, lambda self: None)
+ self.tw.lc.def_prim(
+ 'nop1', 0,
+ Primitive(self.tw.lc.prim_define_stack,
+ arg_descs=[ConstantArg('stack1')]))
palette.add_block('hat2',
hidden=True,
@@ -1028,9 +1153,11 @@ variable'))
prim_name='nop2',
logo_command='to stack2\n',
help_string=_('top of Action 2 stack'))
- self.tw.lc.def_prim('nop2', 0, lambda self: None)
+ self.tw.lc.def_prim(
+ 'nop2', 0,
+ Primitive(self.tw.lc.prim_define_stack,
+ arg_descs=[ConstantArg('stack2')]))
- primitive_dictionary['stack1'] = self._prim_stack1
palette.add_block('stack1',
hidden=True,
style='basic-style-extended-vertical',
@@ -1038,9 +1165,12 @@ variable'))
prim_name='stack1',
logo_command='stack1',
help_string=_('invokes Action 1 stack'))
- self.tw.lc.def_prim('stack1', 0, primitive_dictionary['stack1'], True)
+ self.tw.lc.def_prim(
+ 'stack1', 0,
+ Primitive(self.tw.lc.prim_invoke_stack,
+ arg_descs=[ConstantArg('stack1')]),
+ True)
- primitive_dictionary['stack2'] = self._prim_stack2
palette.add_block('stack2',
hidden=True,
style='basic-style-extended-vertical',
@@ -1048,16 +1178,19 @@ variable'))
prim_name='stack2',
logo_command='stack2',
help_string=_('invokes Action 2 stack'))
- self.tw.lc.def_prim('stack2', 0, primitive_dictionary['stack2'], True)
+ self.tw.lc.def_prim(
+ 'stack2', 0,
+ Primitive(self.tw.lc.prim_invoke_stack,
+ arg_descs=[ConstantArg('stack2')]),
+ True)
def _trash_palette(self):
''' The basic Turtle Art turtle palette '''
- debug_output('creating %s palette' % _('trash'),
- self.tw.running_sugar)
palette = make_palette('trash',
colors=["#FFFF00", "#A0A000"],
- help_string=_('trash'))
+ help_string=_('trash'),
+ translation=_('trash'))
palette.add_block('empty',
style='blank-style',
@@ -1074,19 +1207,9 @@ variable'))
label=_('clear all'),
help_string=_('move all blocks to trash'))
- # Block primitives
+ # Callbacks to update labels after executing a block
- def _prim_clear(self):
- self.tw.lc.prim_clear()
- self.tw.turtles.reset_turtles()
-
- def _prim_and(self, x, y):
- ''' Logical and '''
- return x & y
-
- def _prim_arc(self, cmd, value1, value2):
- ''' Turtle draws an arc of degree, radius '''
- cmd(float(value1), float(value2))
+ def after_arc(self, *ignored_args):
if self.tw.lc.update_values:
self.tw.lc.update_label_value(
'xcor',
@@ -1100,65 +1223,8 @@ variable'))
'heading',
self.tw.turtles.get_active_turtle().get_heading())
- def _prim_box(self, x):
- ''' Retrieve value from named box '''
- if isinstance(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_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,
- reverse=False):
- ''' Turtle moves by method specified in value1 '''
- pos = None
- if isinstance(value1, (tuple, list)):
- pos = value1
- value1 = pos[0]
- value2 = pos[1]
- if not _num_type(value1):
- raise logoerror("#notanumber")
- if value2 is None:
- if reverse:
- cmd(float(-value1))
- else:
- cmd(float(value1))
- else:
- if not _num_type(value2):
- raise logoerror("#notanumber")
- if pos is not None:
- cmd((float(value1), float(value2)), pendown=pendown)
- else:
- cmd(float(value1), float(value2), pendown=pendown)
+ def after_move(self, *ignored_args, **ignored_kwargs):
+ ''' Update labels after moving the turtle '''
if self.tw.lc.update_values:
self.tw.lc.update_label_value(
'xcor',
@@ -1169,323 +1235,38 @@ variable'))
self.tw.turtles.get_active_turtle().get_xy()[1] /
self.tw.coord_scale)
- def _prim_or(self, x, y):
- ''' Logical or '''
- return x | y
-
- def _prim_repeat(self, num, blklist):
- ''' Repeat list num times. '''
- if not _num_type(num):
- raise logoerror("#notanumber")
- 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, reverse=False):
- ''' Turtle rotates clockwise '''
- if not _num_type(value):
- raise logoerror("#notanumber")
- if reverse:
- self.tw.turtles.get_active_turtle().right(float(-value))
- else:
- self.tw.turtles.get_active_turtle().right(float(value))
+ def after_right(self, *ignored_args):
if self.tw.lc.update_values:
self.tw.lc.update_label_value(
'heading',
self.tw.turtles.get_active_turtle().get_heading())
- def _prim_set(self, name, cmd, value=None):
- ''' Set a value and update the associated value blocks '''
+ def after_set(self, name, value=None):
+ ''' Update the associated value blocks '''
if value is not None:
- cmd(value)
if self.tw.lc.update_values:
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 isinstance(convert(x, float, False), float):
- if int(float(x)) == x:
- x = int(x)
- self.tw.lc.boxes[name + str(x)] = val
- if self.tw.lc.update_values:
- self.tw.lc.update_label_value('box', val, label=x)
- else:
- self.tw.lc.boxes[name] = val
- if self.tw.lc.update_values:
- self.tw.lc.update_label_value(name, val)
-
- def _prim_stack(self, x):
- ''' Process a named stack '''
- if isinstance(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, wait_time):
- ''' Show the turtle while we wait '''
- self.tw.turtles.get_active_turtle().show()
- endtime = _millisecond() + wait_time * 1000.
- while _millisecond() < endtime:
- sleep(wait_time / 10.)
- yield True
- self.tw.turtles.get_active_turtle().hide()
- self.tw.lc.ireturn()
- yield True
-
- # Math primitivies
-
- def _prim_careful_divide(self, x, y):
- ''' Raise error on divide by zero '''
- if isinstance(x, list) and _num_type(y):
- z = []
- for i in range(len(x)):
- try:
- z.append(x[i] / y)
- except ZeroDivisionError:
- raise logoerror("#zerodivide")
- return z
- 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 '''
- if isinstance(x, list) and isinstance(y, list):
- for i in range(len(x)):
- if x[i] != y[i]:
- return False
- return True
- 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("#syntaxerror")
-
- def _prim_less(self, x, y):
- ''' Compare numbers and strings '''
- if isinstance(x, list) or isinstance(y, list):
- raise logoerror("#syntaxerror")
- 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 x in COLORDICT:
- x = _color_to_num(x)
- if y in COLORDICT:
- y = _color_to_num(y)
- if _num_type(x) and _num_type(y):
- return(x + y)
- elif isinstance(x, list) and isinstance(y, list):
- z = []
- for i in range(len(x)):
- z.append(x[i] + y[i])
- return(z)
- 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)
- elif isinstance(x, list) and isinstance(y, list):
- z = []
- for i in range(len(x)):
- z.append(x[i] - y[i])
- return(z)
- 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)
- elif isinstance(x, list) and _num_type(y):
- z = []
- for i in range(len(x)):
- z.append(x[i] * y)
- return(z)
- elif isinstance(y, list) and _num_type(x):
- z = []
- for i in range(len(y)):
- z.append(y[i] * x)
- return(z)
- 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 isinstance(x, (int, float)):
- return(x)
- try:
- return int(ord(x))
- except TypeError:
- pass
- if isinstance(x, list):
- raise logoerror("#syntaxerror")
- if x in COLORDICT:
- return _color_to_num(x)
- xx = convert(x.replace(self.tw.decimal_point, '.'), float)
- if isinstance(xx, float):
- return xx
- else:
- xx, xflag = chr_to_ord(x)
- if xflag:
- return xx
- else:
- raise logoerror("#syntaxerror")
-
- def _make_constant(self, palette, block_name, label, constant):
+ def _make_constant(self, palette, block_name, label, constant_key):
''' Factory for constant blocks '''
- if constant in COLORDICT:
- if COLORDICT[constant][0] is not None:
- value = str(COLORDICT[constant][0])
+ constant = CONSTANTS[constant_key]
+ if isinstance(constant, Color):
+ if constant.color is not None:
+ logo_command = str(constant.color)
else:
# Black or White
- value = '0 tasetshade %d' % (COLORDICT[constant][1])
+ logo_command = '0 tasetshade %d' % (constant.shade)
+ return_type = TYPE_COLOR
else:
- value = constant
+ logo_command = constant
+ return_type = TYPE_NUMBER
palette.add_block(block_name,
style='box-style',
label=label,
prim_name=block_name,
- logo_command=value)
- self.tw.lc.def_prim(block_name, 0, lambda self: constant)
+ logo_command=logo_command)
+ self.tw.lc.def_prim(block_name, 0,
+ Primitive(CONSTANTS.get, return_type=return_type,
+ arg_descs=[ConstantArg(constant_key)]))