From ea3a04bb097a57621224e9894e02b1b0d13895cc Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Tue, 01 Mar 2011 22:54:55 +0000 Subject: refactoring of palette and block generation: a class for each palette and block rather than giant dictionaries --- (limited to 'TurtleArt/tabasics.py') 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() -- cgit v0.9.1