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 --- 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() diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py index 80738fa..bbff803 100644 --- a/TurtleArt/taconstants.py +++ b/TurtleArt/taconstants.py @@ -19,79 +19,6 @@ #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, it is generally a -matter of modifying some tables below and then adding the primitive to -talogo.py. For example, if we want to add a new turtle command, -'uturn', we'd make the following changes: - -(1) We'd add 'uturn' to the PALETTES list of lists: - -PALETTES = [['forward', 'back', 'clean', 'left', 'right', 'uturn', 'show', - 'seth', 'setxy', 'heading', 'xcor', 'ycor', 'setscale', - 'arc', 'scale'], - ['penup','pendown', 'setpensize', 'fillscreen', 'pensize',... - -(2) Then we'd add it to one of the block-style definitions. Since it takes -no arguments, we'd add it here: - -BASIC_STYLE = ['clean', 'penup', 'pendown', 'stack1', 'stack2', 'vspace', - 'hideblocks', 'showblocks', 'clearheap', 'printheap', 'kbinput', 'uturn'] - -(3) Then we give it a name (Note the syntax _('string to be -translated') used by the language-internationalization system; also -note that the name is an array, as some blocks contain multiple -strings.): - -BLOCK_NAMES = { -... - 'uturn':[_('u-turn')], -... - } - -(4) and a help-menu entry: - -HELP_STRINGS = { -... - 'uturn':_('change the heading of the turtle 180 degrees'), -... - } - -(5) Next, we need to define it as a primitive for the Logo command -parser (generally just the same name): - -PRIMITIVES = { -... - 'uturn':'uturn', -... - } - -(6) Since there are no default arguments, we don't need to do anything -else here. But we do need to define the actual function in talogo.py - -DEFPRIM = { -... - 'uturn':[0, lambda self: self.tw.canvas.seth(self.tw.canvas.heading+180)], -... - } - -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: (1) adding an additional -entry to PALETTE_NAMES; (2) new list of blocks to PALETTES; and (3) an -additional entry in COLORS. However you will have to: (4) 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 gettext import gettext as _ # @@ -112,47 +39,11 @@ TOP_LAYER = 1000 # Block-palette categories # -PALETTE_NAMES = ['turtle', 'pen', 'colors', 'numbers', 'flow', 'blocks', - 'media', 'sensor', 'extras', 'portfolio', 'trash'] - -PALETTES = [['forward', 'back', 'clean', 'left', 'right', - 'arc', 'setxy2', 'seth', 'xcor', 'ycor', 'heading'], - ['penup', 'pendown', 'setpensize', 'fillscreen', 'pensize', - 'startfill', 'stopfill'], - ['setcolor', 'setshade', 'setgray', 'color', 'shade', 'gray', - 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', - 'white', 'black'], - ['plus2', 'minus2', 'product2', - 'division2', 'identity2', 'remainder2', 'sqrt', 'random', - 'number', 'greater2', 'less2', 'equal2', 'not', 'and2', 'or2'], - ['wait', 'forever', 'repeat', 'if', 'ifelse', 'while', 'until', - 'hspace', 'vspace', 'stopstack'], - ['start', 'storeinbox1', 'storeinbox2', 'string', 'box1', 'box2', - 'box', 'storein', 'hat', 'hat1', 'hat2', 'stack', 'stack1', - 'stack2'], - ['journal', 'audio', 'video', 'description', 'string', - 'show', 'setscale', 'savepix', 'savesvg', 'scale', 'mediawait'], - ['kbinput', 'keyboard', 'readpixel', 'see', 'time'], - ['push', 'printheap', 'clearheap', 'pop', 'comment', 'print', - 'myfunc1arg', 'userdefined', 'cartesian', 'polar', 'addturtle', - 'reskin', 'sandwichtop_no_label', 'sandwichbottom'], - ['hideblocks', 'showblocks', 'fullscreen', 'picturelist', - 'picture1x1a', 'picture1x1', 'picture2x2', 'picture2x1', - 'picture1x2', 'leftpos', 'bottompos', 'width', 'rightpos', - 'toppos', 'height'], - ['empty', 'restoreall']] - -# -# Block-style attributes -# - -COLORS = [["#00FF00", "#00A000"], ["#00FFFF", "#00A0A0"], - ["#00FFFF", "#00A0A0"], ["#FF00FF", "#A000A0"], - ["#FFC000", "#A08000"], ["#FFFF00", "#A0A000"], - ["#A0FF00", "#A0A000"], ["#FF6060", "#A06060"], - ["#FF0000", "#A00000"], ["#6060FF", "#6060A0"], - ["#FFFF00", "#A0A000"]] +PALETTE_NAMES = [] +PALETTES = [] +COLORS = [] +# Special-case some block colors BOX_COLORS = {'red': ["#FF0000", "#A00000"], 'orange': ["#FFD000", "#AA8000"], 'yellow': ["#FFFF00", "#A0A000"], @@ -194,59 +85,47 @@ UNKNOWN = 'unknown' # # Block-style definitions # -BASIC_STYLE_HEAD = ['start', 'hat1', 'hat2', 'restore', 'restoreall'] -BASIC_STYLE_HEAD_1ARG = ['hat'] -BASIC_STYLE_TAIL = ['stopstack', 'empty'] +# TODO: define depreciated blocks +BASIC_STYLE_HEAD = [] +BASIC_STYLE_HEAD_1ARG = [] +BASIC_STYLE_TAIL = [] BASIC_STYLE = [] -BASIC_STYLE_EXTENDED_VERTICAL = ['clean', 'penup', 'pendown', 'stack1', - 'stack2', 'hideblocks', 'showblocks', 'clearheap', 'printheap', 'kbinput', - 'fullscreen', 'cartesian', 'polar', 'startfill', 'mediawait', - 'stopfill', 'readpixel', 'vspace'] -INVISIBLE = ['sandwichcollapsed'] -BASIC_STYLE_EXTENDED = ['picturelist', 'picture1x1', 'picture2x2', - 'picture2x1', 'picture1x2', 'picture1x1a'] -BASIC_STYLE_1ARG = ['forward', 'back', 'left', 'right', 'seth', 'show', - 'setscale', 'setpensize', 'setcolor', 'setshade', 'print', 'showaligned', - 'settextsize', 'settextcolor', 'print', 'wait', 'storeinbox1', 'savepix', - 'storeinbox2', 'wait', 'stack', 'push', 'nop', 'addturtle', 'comment', - 'image', 'savesvg', 'setgray', 'skin', 'reskin'] -BASIC_STYLE_VAR_ARG = ['userdefined', 'userdefined2args', 'userdefined3args'] +BASIC_STYLE_EXTENDED_VERTICAL = [] +INVISIBLE = [] +BASIC_STYLE_EXTENDED = [] +BASIC_STYLE_1ARG = ['settextsize', 'settextcolor', 'nop'] +BASIC_STYLE_VAR_ARG = [] BULLET_STYLE = ['templatelist', 'list'] -BASIC_STYLE_2ARG = ['arc', 'setxy', 'setxy2', 'fillscreen', 'storein', 'write'] -BOX_STYLE = ['number', 'xcor', 'ycor', 'heading', 'pensize', 'color', 'shade', - 'textcolor', 'textsize', 'box1', 'box2', 'string', 'leftpos', 'scale', - 'toppos', 'rightpos', 'bottompos', 'width', 'height', 'pop', 'keyboard', - 'red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'white', - 'black', 'titlex', 'titley', 'leftx', 'topy', 'rightx', 'bottomy', - 'gray', 'see', 'time'] -BOX_STYLE_MEDIA = ['description', 'audio', 'journal', 'video'] -NUMBER_STYLE = ['plus2', 'product2', 'myfunc'] -NUMBER_STYLE_VAR_ARG = ['myfunc1arg', 'myfunc2arg', 'myfunc3arg'] -NUMBER_STYLE_BLOCK = ['random'] -NUMBER_STYLE_PORCH = ['minus2', 'division2', 'remainder2'] -NUMBER_STYLE_1ARG = ['sqrt', 'identity2'] -NUMBER_STYLE_1STRARG = ['box'] -COMPARE_STYLE = ['equal2'] -COMPARE_PORCH_STYLE = ['greater2', 'less2'] -BOOLEAN_STYLE = ['and2', 'or2'] -NOT_STYLE = ['not'] -FLOW_STYLE = ['forever'] -FLOW_STYLE_TAIL = ['hspace'] -FLOW_STYLE_1ARG = ['repeat'] -FLOW_STYLE_BOOLEAN = ['if', 'while', 'until'] -FLOW_STYLE_WHILE = ['while2'] -FLOW_STYLE_ELSE = ['ifelse'] -COLLAPSIBLE_TOP = ['sandwichtop'] -COLLAPSIBLE_TOP_NO_ARM = ['sandwichtop_no_arm'] -COLLAPSIBLE_TOP_NO_LABEL = ['sandwichtop_no_label'] -COLLAPSIBLE_TOP_NO_ARM_NO_LABEL = ['sandwichtop_no_arm_no_label'] -COLLAPSIBLE_BOTTOM = ['sandwichbottom'] +BASIC_STYLE_2ARG = [] +BOX_STYLE = ['textsize'] +BOX_STYLE_MEDIA = [] +NUMBER_STYLE = ['myfunc'] +NUMBER_STYLE_VAR_ARG = [] +NUMBER_STYLE_BLOCK = [] +NUMBER_STYLE_PORCH = [] +NUMBER_STYLE_1ARG = [] +NUMBER_STYLE_1STRARG = [] +COMPARE_STYLE = [] +COMPARE_PORCH_STYLE = [] +BOOLEAN_STYLE = [] +NOT_STYLE = [] +FLOW_STYLE = [] +FLOW_STYLE_TAIL = [] +FLOW_STYLE_1ARG = [] +FLOW_STYLE_BOOLEAN = [] +FLOW_STYLE_WHILE = [] +FLOW_STYLE_ELSE = [] +COLLAPSIBLE_TOP = [] +COLLAPSIBLE_TOP_NO_ARM = [] +COLLAPSIBLE_TOP_NO_LABEL = [] +COLLAPSIBLE_TOP_NO_ARM_NO_LABEL = [] +COLLAPSIBLE_BOTTOM = [] # Depreciated block styles -PORTFOLIO_STYLE_2x2 = ['template2x2'] -PORTFOLIO_STYLE_1x1 = ['template1x1', 'template1x1a'] -PORTFOLIO_STYLE_2x1 = ['template2x1'] -PORTFOLIO_STYLE_1x2 = ['template1x2'] +PORTFOLIO_STYLE_2x2 = [] +PORTFOLIO_STYLE_1x1 = [] +PORTFOLIO_STYLE_2x1 = [] +PORTFOLIO_STYLE_1x2 = [] BLOCK_STYLES = {'basic-style-head': BASIC_STYLE_HEAD, 'basic-style-head-1arg': BASIC_STYLE_HEAD_1ARG, @@ -291,11 +170,12 @@ BLOCK_STYLES = {'basic-style-head': BASIC_STYLE_HEAD, # # Blocks that are expandable # +EXPANDABLE_STYLE = ['boolean-style', 'compare-porch-style', 'compare-style', + 'number-style-porch', 'number-style', 'basic-style-2arg'] + EXPANDABLE = ['vspace', 'hspace', 'identity2'] -EXPANDABLE_BLOCKS = ['plus2', 'minus2', 'division2', 'remainder2', 'product2', - 'random', 'equal2', 'greater2', 'less2', 'and2', 'or2', - 'arc', 'setxy', 'setxy2', 'fillscreen', 'storein', 'write'] +EXPANDABLE_BLOCKS = [] EXPANDABLE_ARGS = ['templatelist', 'list', 'myfunc1arg', 'myfunc2arg', 'myfunc3arg', 'userdefined', 'userdefined2args', @@ -337,376 +217,30 @@ CONSTANTS = {'leftpos': None, 'toppos': None, 'rightpos': None, # Block-name dictionary used for labels # BLOCK_NAMES = { - 'addturtle': [_('turtle')], - 'and2': [_('and')], - 'arc': [_('arc'), _('angle'), _('radius')], - 'audio': [' '], - 'back': [_('back')], - 'black': [_('black')], - 'blocks': [_('blocks')], - 'blue': [_('blue')], - 'bottompos': [_('bottom')], - 'bottomy': [_('picture bottom')], - 'box': [_('box')], - 'box1': [_('box 1')], - 'box2': [_('box 2')], - 'cartesian': [_('Cartesian')], - 'clean': [_(' clean ')], - 'clearheap': [_('empty heap')], - 'color': [_('color')], - 'colors': [_('colors')], - 'comment': [_('comment')], - 'cyan': [_('cyan')], - 'decription': [' '], - 'division2': ['/'], - 'empty': [_('empty trash')], - 'equal2': ['='], - 'extras': [_('extras')], - 'fillscreen': [_('fill screen'), _('color'), _('shade')], - 'flow': [_('flow')], - 'forever': [_('forever')], - 'forward': [_('forward')], - 'fullscreen': [_('full screen')], - 'gray': [_('gray')], - 'greater2': ['>'], - 'green': [_('green')], - 'hat': [_('action')], - 'hat1': [_('action 1')], - 'hat2': [_('action 2')], - 'heading': [_('heading')], - 'height': [_('height')], - 'hideblocks': [_('hide blocks')], - 'hspace': [' '], - 'identity2': ['←'], - 'if': [' ', _('if'), _('then')], - 'ifelse': [' ', _('if'), _('then else')], - 'image': [_('show')], - 'journal': [' '], - 'kbinput': [_('query keyboard')], - 'keyboard': [_('keyboard')], - 'left': [_('left')], - 'leftpos': [_('left')], - 'leftx': [_('picture left')], - 'less2': ['<'], 'list': ['list'], - 'mediawait': [_('media wait')], - 'minus2': ['–'], 'myfunc': [_('Python'), 'f(x)', 'x'], - 'myfunc1arg': [_('Python'), 'f(x)', 'x'], - 'myfunc2arg': [_('Python'), 'f(x,y)', ' '], - 'myfunc3arg': [_('Python'), 'f(x,y,z)', ' '], 'nop': [_(' ')], - 'not': [_('not')], - 'number': ['100'], - 'numbers': [_('numbers')], - 'orange': [_('orange')], - 'or2': [_('or')], - 'pen': [_('pen')], - 'pendown': [_('pen down')], - 'pensize': [_('pen size')], - 'penup': [_('pen up')], - 'picturelist': [' '], - 'picture1x1': [' '], - 'picture1x1a': [' '], - 'picture2x2': [' '], - 'picture2x1': [' '], - 'picture1x2': [' '], - 'pitch': [_('pitch')], - 'plus2': ['+'], - 'polar': [_('polar')], - 'pop': [_('pop')], - 'portfolio': [_('portfolio')], - 'printheap': [_('show heap')], - 'print': [_('print')], - 'product2': ['×'], - 'purple': [_('purple')], - 'push': [_('push')], - 'random': [_('random'), _('min'), _('max')], - 'readpixel': [_('read pixel')], - 'red': [_('red')], - 'remainder2': [_('mod')], - 'repeat': [' ', _('repeat')], - 'reskin': [_('turtle shell')], - 'resistance': [_('resistance')], - 'restore': [_('restore last')], - 'restoreall': [_('restore all')], - 'right': [_('right')], - 'rightpos': [_('right')], - 'rightx': [_('picture right')], - 'savepix': [_('save picture')], - 'savesvg': [_('save SVG')], - 'sandwichbottom': [' ', ' '], - 'sandwichcollapsed': [' '], - 'sandwichtop': [_('top of stack')], - 'sandwichtop_no_arm': [_('top of stack')], - 'sandwichtop_no_label': [' ', ' '], - 'sandwichtop_no_arm_no_label': [' ', _('click to open')], - 'scale': [_('scale')], - 'see': [_('turtle sees')], - 'sensor': [_('sensors')], - 'setcolor': [_('set color')], - 'setgray': [_('set gray')], - 'seth': [_('set heading')], - 'setpensize': [_('set pen size')], - 'setscale': [_('set scale')], - 'setshade': [_('set shade')], - 'settextcolor': [_('set text color')], 'settextsize': [_('set text size')], - 'setxy': [_('set xy'), _('x'), _('y')], - 'setxy2': [_('set xy'), _('x'), _('y')], - 'shade': [_('shade')], - 'show': [_('show')], - 'showblocks': [_('show blocks')], - 'showaligned': [_('show aligned')], - 'skin': [_('turtle shell')], - 'sound': [_('sound')], - 'sqrt': ['√'], - 'stack': [_('action')], - 'stack1': [_('action 1')], - 'stack2': [_('action 2')], - 'start': [_('start')], - 'startfill': [_('start fill')], - 'stopfill': [_('end fill')], - 'stopstack': [_('stop action')], - 'storein': [_('store in'), _('box'), _('value')], - 'storeinbox1': [_('store in box 1')], - 'storeinbox2': [_('store in box 2')], - 'string': [_('text')], - 'template1x1': [' '], - 'template1x1a': [' '], - 'template1x2': [' '], - 'template2x1': [' '], - 'template2x2': [' '], - 'templatelist': [' '], - 'textsize': [_('text size')], - 'time': [_('time')], - 'titlex': [_('title x')], - 'titley': [_('title y')], - 'toppos': [_('top')], - 'topy': [_('picture top')], - 'trash': [_('trash')], - 'turtle': [_('turtle')], - 'until': [_('until')], - 'userdefined': [_(' ')], - 'userdefined2args': [_(' ')], - 'userdefined3args': [_(' ')], - 'video': [' '], - 'voltage': [_('voltage')], - 'volume': [_('volume')], - 'vspace': [' '], - 'wait': [_('wait')], - 'while': [_('while')], - 'while2': [_('while')], - 'white': [_('white')], - 'width': [_('width')], - 'write': [_('write')], - 'xcor': [_('xcor')], - 'ycor': [_('ycor')], - 'yellow': [_('yellow')]} + 'textsize': [_('text size')]} # # Logo primitives # - +# TODO: check hats (nop1, 2, 3), setxy PRIMITIVES = { - 'addturtle': 'turtle', - 'and2': 'and', - 'arc': 'arc', - 'back': 'back', - 'black': 'black', - 'blue': 'blue', - 'bottompos': 'bpos', - 'bottomy': 'boty', - 'box1': 'box1', - 'box2': 'box2', - 'box': 'box', - 'cartesian': 'cartesian', - 'clean': 'clean', - 'clearheap': 'clearheap', - 'color': 'color', - 'comment': 'comment', - 'cyan': 'cyan', - 'division2': 'division', - 'equal2': 'equal?', - 'fillscreen': 'fillscreen', - 'forever': 'forever', - 'forward': 'forward', - 'fullscreen': 'fullscreen', - 'gray': 'gray', - 'greater2': 'greater?', - 'green': 'green', - 'hat': 'nop3', - 'hat1': 'nop1', - 'hat2': 'nop2', - 'heading': 'heading', - 'height': 'vres', - 'hideblocks': 'hideblocks', - 'hspace': 'nop', - 'identity2': 'id', - 'if': 'if', - 'ifelse': 'ifelse', - 'image': 'show', - 'kbinput': 'kbinput', - 'keyboard': 'keyboard', - 'left': 'left', - 'leftpos': 'lpos', - 'leftx': 'leftx', - 'less2': 'less?', 'list': 'bulletlist', - 'mediawait': 'mediawait', - 'minus2': 'minus', 'myfunc': 'myfunction', - 'myfunc1arg': 'myfunction', - 'myfunc2arg': 'myfunction2', - 'myfunc3arg': 'myfunction3', 'nop': 'userdefined', - 'not': 'not', - 'orange': 'orange', - 'or2': 'or', - 'pendown': 'pendown', - 'pensize': 'pensize', - 'penup': 'penup', - 'plus2': 'plus', - 'polar': 'polar', - 'pop': 'pop', - 'printheap': 'printheap', - 'print': 'print', - 'product2': 'product', - 'purple': 'purple', - 'push': 'push', - 'random': 'random', - 'red': 'red', - 'readpixel': 'readpixel', - 'remainder2': 'mod', - 'repeat': 'repeat', - 'right': 'right', - 'rightpos': 'rpos', - 'rightx': 'rightx', - 'sandwichtop': 'comment', - 'sandwichtop_no_arm': 'comment', - 'sandwichtop_no_label': 'nop', - 'sandwichtop_no_arm_no_label': 'nop', - 'sandwichbottom': 'nop', - 'sandwichcollapsed': 'nop', - 'savepix': 'savepix', - 'savesvg': 'savesvg', - 'see': 'see', - 'scale': 'scale', - 'setcolor': 'setcolor', - 'setgray': 'setgray', - 'seth': 'seth', - 'setpensize': 'setpensize', - 'setscale': 'setscale', - 'setshade': 'setshade', 'settextsize': 'settextsize', - 'settextcolor': 'settextcolor', - 'setxy': 'setxy', - 'setxy2': 'setxy2', - 'shade': 'shade', - 'show': 'show', - 'showblocks': 'showblocks', - 'showaligned': 'showaligned', - 'skin': 'skin', - 'sqrt': 'sqrt', - 'stack': 'stack', - 'stack1': 'stack1', - 'stack2': 'stack2', - 'start': 'start', - 'startfill': 'startfill', - 'stopfill': 'stopfill', - 'stopstack': 'stopstack', - 'storein': 'storeinbox', - 'storeinbox1': 'storeinbox1', - 'storeinbox2': 'storeinbox2', - 'template1x1': 't1x1', - 'template1x1a': 't1x1a', - 'template1x2': 't1x2', - 'template2x1': 't2x1', - 'template2x2': 't2x2', - 'templatelist': 'bullet', - 'textsize': 'textsize', - 'time': 'time', - 'titlex': 'titlex', - 'titley': 'titley', - 'toppos': 'tpos', - 'topy': 'topy', - 'userdefined': 'userdefined', - 'userdefined2args': 'userdefined2', - 'userdefined3args': 'userdefined3', - 'vspace': 'nop', - 'wait': 'wait', - 'while2': 'while', - 'white': 'white', - 'width': 'hres', - 'write': 'write', - 'xcor': 'xcor', - 'ycor': 'ycor', - 'yellow': 'yellow'} + 'textsize': 'textsize'} # # block default values # DEFAULTS = { - 'addturtle': [1], - 'arc': [90, 100], - 'audio': [None], - 'back': [100], - 'box': [_('my box')], - 'comment': [_('comment')], - 'description': [None], - 'fillscreen': [60, 80], - 'forever': [None, 'vspace'], - 'forward': [100], - 'hat': [_('action')], - 'if': [None, None, 'vspace'], - 'ifelse': [None, 'vspace', None, 'vspace'], - 'journal': [None], - 'left': [90], - 'list': ['∙ ', '∙ '], - 'media': [None], 'myfunc': ['x', 100], - 'myfunc1arg': ['x', 100], - 'myfunc2arg': ['x+y', 100, 100], - 'myfunc3arg': ['x+y+z', 100, 100, 100], - 'nop': [100], - 'number': [100], - 'random': [0, 100], - 'repeat': [4, None, 'vspace'], - 'right': [90], - 'sandwichtop': [_('label')], - 'sandwichtop_no_arm': [_('label')], - 'savepix': [_('picture name')], - 'savesvg': [_('picture name')], - 'setcolor': [0], - 'setgray': [100], - 'seth': [0], - 'setpensize': [5], - 'setscale': [33], - 'setshade': [50], - 'settextsize': [48], - 'settextcolor': [0], - 'setxy': [0, 0], - 'setxy2': [0, 0], - 'show': [_('text')], - 'showaligned': [_('text')], - 'stack': [_('action')], - 'storeinbox1': [100], - 'storeinbox2': [100], - 'storein': [_('my box'), 100], - 'string': [_('text')], - 'template1x1': [_('Title'), 'None'], - 'template1x1a': [_('Title'), 'None'], - 'template1x2': [_('Title'), 'None', 'None'], - 'template2x1': [_('Title'), 'None', 'None'], - 'template2x2': [_('Title'), 'None', 'None', 'None', 'None'], - 'templatelist': [_('Title'), '∙ '], - 'userdefined': [100], - 'userdefined2args': [100, 100], - 'userdefined3args': [100, 100, 100], - 'video': [None], - 'wait': [1], - 'write': [_('text'), 32]} + 'nop': [100]} # # Blocks that can interchange strings and numbers for their arguments @@ -763,7 +297,7 @@ OLD_NAMES = {'product': 'product2', 'storeinbox': 'storein', 'minus': 'minus2', 'template1': 'template1x1', 'template2': 'template2x1', 'template6': 'template1x2', 'template7': 'template2x2', 'template4': 'template1x1a', 'hres': 'width', 'vres': 'height', - 'sandwichtop2': 'sandwichtop'} + 'sandwichtop2': 'sandwichtop', 'image': 'show'} # # Define the relative size and postion of media objects @@ -786,215 +320,30 @@ TEMPLATES = {'t1x1': (0.5, 0.5, 0.0625, 0.125, 1.05, 0), # Names for blocks without names for popup help # SPECIAL_NAMES = { - 'and2': _('and'), - 'audio': _('audio'), - 'description': _('description'), - 'division2': _('divide'), - 'equal2': _('equal'), - 'greater2': _('greater than'), - 'hspace': _('horizontal space'), - 'identity2': _('identity'), - 'if': _('if then'), - 'ifelse': _('if then else'), - 'journal': _('journal'), - 'less2': _('less than'), - 'or2': _('or'), - 'minus2': _('minus'), - 'nop': _('Python code'), - 'number': _('number'), - 'plus2': _('plus'), - 'product2': _('multiply'), - 'remainder2': _('mod'), - 'repeat': _('repeat'), - 'sandwichtop_no_label': _('top of a collapsible stack'), - 'sandwichbottom': _('bottom of a collapsible stack'), - 'sensors': _('sensors'), - 'sqrt': _('square root'), - 'template1x1': _('presentation 1x1'), - 'template1x1a': _('presentation 1x1'), - 'template1x2': _('presentation 1x2'), - 'template2x1': _('presentation 2x1'), - 'template2x2': _('presentation 2x2'), - 'templatelist': _('presentation bulleted list'), - 'textsize': _('text size'), - 'userdefined': _('Python block'), - 'userdefined2args': _('Python block'), - 'userdefined3args': _('Python block'), - 'video': _('video'), - 'vspace': _('vertical space')} + 'textsize': _('text size')} # # Help messages # HELP_STRINGS = { - 'addturtle': _("chooses which turtle to command"), - 'and2': _("logical AND operator"), - 'arc': _("moves turtle along an arc"), - 'audio': _("Sugar Journal audio object"), - 'back': _("moves turtle backward"), - 'blocks': _("Palette of variable blocks"), - 'bottompos': _("ycor of bottom of screen"), - 'box1': _("Variable 1 (numeric value)"), - 'box2': _("Variable 2 (numeric value)"), - 'box': _("named variable (numeric value)"), 'cartesian': _("displays Cartesian coordinates"), 'clean': _("clears the screen and reset the turtle"), - 'clearheap': _("emptys FILO (first-in-last-out heap)"), - 'color': _( - "holds current pen color (can be used in place of a number block)"), - 'colors': _("Palette of pen colors"), - 'comment': _("places a comment in your code"), 'debugoff': _("Debug"), - 'description': _("Sugar Journal description field"), - 'division2': _("divides top numeric input (numerator) by bottom numeric input (denominator)"), - 'empty': _("permanently deletes items in trash"), 'eraseron': _("Clean"), - 'equal2': _("logical equal-to operator"), - 'extras': _("Palette of extra options"), - 'fillscreen': _("fills the background with (color, shade)"), - 'flow': _("Palette of flow operators"), - 'forever': _("loops forever"), - 'forward': _("moves turtle forward"), - 'fullscreen': _("hides the Sugar toolbars"), - 'gray': _( - "holds current gray level (can be used in place of a number block)"), - 'greater2': _("logical greater-than operator"), - 'hat1': _("top of Action 1 stack"), - 'hat2': _("top of Action 2 stack"), - 'hat': _("top of nameable action stack"), - 'heading': _("holds current heading value of the turtle (can be used in place of a number block)"), - 'height': _("the canvas height"), - 'hideblocks': _("declutters canvas by hiding blocks"), - 'hideshowoff': _("Hide blocks"), - 'hspace': _("jogs stack right"), - 'identity2': _("identity operator used for extending blocks"), - 'ifelse': _("if-then-else operator that uses boolean operators from Numbers palette"), - 'if': _( - "if-then operator that uses boolean operators from Numbers palette"), - 'journal': _("Sugar Journal media object"), - 'kbinput': _("query for keyboard input (results stored in keyboard block)"), - 'keyboard': _("holds results of query-keyboard block"), - 'leftpos': _("xcor of left of screen"), - 'left': _("turns turtle counterclockwise (angle in degrees)"), - 'less2': _("logical less-than operator"), - 'media': _("Palette of media objects"), - 'mediawait': _("wait for current video or audio to complete"), - 'minus2': _("subtracts bottom numeric input from top numeric input"), 'myfunc': _("a programmable block: used to add advanced math equations, e.g., sin(x)"), - 'myfunc1arg': _("a programmable block: used to add advanced single-variable math equations, e.g., sin(x)"), - 'myfunc2arg': _("a programmable block: used to add advanced multi-variable math equations, e.g., sqrt(x*x+y*y)"), - 'myfunc3arg': _("a programmable block: used to add advanced multi-variable math equations, e.g., sin(x+y+z)"), 'next': _('displays next palette'), 'nop': _("runs code found in the tamyblock.py module found in the Journal"), - 'not': _("logical NOT operator"), - 'numbers': _("Palette of numeric operators"), - 'number': _("used as numeric input in mathematic operators"), - 'or2': _("logical OR operator"), 'orientation': _("changes the orientation of the palette of blocks"), - 'pendown': _("Turtle will draw when moved."), - 'pen': _("Palette of pen commands"), - 'pensize': _( - "holds current pen size (can be used in place of a number block)"), - 'penup': _("Turtle will not draw when moved."), - 'picture1x1': _( - "presentation template: select Journal object (with description)"), - 'picture1x1a': _( - "presentation template: select Journal object (no description)"), - 'picture1x2': _("presentation template: select two Journal objects"), - 'picture2x1': _("presentation template: select two Journal objects"), - 'picture2x2': _("presentation template: select four Journal objects"), - 'picturelist': _("presentation template: list of bullets"), - 'plus2': _("adds two alphanumeric inputs"), 'polar': _("displays polar coordinates"), - 'pop': _("pops value off FILO (first-in last-out heap)"), - 'portfolio': _("Palette of presentation templates"), - 'print': _("prints value in status block at bottom of the screen"), - 'printheap': _("shows values in FILO (first-in last-out heap)"), - 'product2': _("multiplies two numeric inputs"), - 'push': _("pushes value onto FILO (first-in last-out heap)"), - 'random': _("returns random number between minimum (top) and maximum (bottom) values"), - 'readpixel': _("RGB color under the turtle is pushed to the stack"), - 'remainder2': _("modular (remainder) operator"), - 'repeat': _("loops specified number of times"), - 'resistance': _("sensor input resistance"), - 'reskin': _("put a custom 'shell' on the turtle"), - 'restore': _("restores most recent blocks from trash"), - 'restoreall': _("restore all blocks from trash"), - 'rightpos': _("xcor of right of screen"), - 'right': _("turns turtle clockwise (angle in degrees)"), 'run-fastoff': _("Run"), 'run-slowoff': _("Step"), - 'sandwichbottom': _( - "bottom block in a collapsibe stack: click to collapse"), - 'sandwichcollapsed': _("bottom block in a collapsed stack: click to open"), - 'sandwichtop': _("top of a collapsible stack"), - 'sandwichtop_no_label': _("top of a collapsed stack"), - 'sandwichtop_no_arm': _("top of a collapsible stack"), - 'sandwichtop_no_arm_no_label': _("top of a collapsed stack"), 'savepix': _("saves a picture to the Sugar Journal"), 'savesvg': _("saves turtle graphics as an SVG file in the Sugar Journal"), - 'scale': _("holds current scale value"), - 'see': _('returns the color that the turtle "sees"'), - 'sensor': _("Palette of sensor blocks"), - 'setcolor': _("sets color of the line drawn by the turtle"), - 'setgray': _("sets gray level of the line drawn by the turtle"), - 'seth': _( - "sets the heading of the turtle (0 is towards the top of the screen.)"), - 'setpensize': _("sets size of the line drawn by the turtle"), - 'setscale': _("sets the scale of media"), - 'setshade': _("sets shade of the line drawn by the turtle"), - 'settextcolor': _("sets color of text drawn by the turtle"), - 'settextsize': _("sets size of text drawn by turtle"), - 'setxy': _("moves turtle to position xcor, ycor; (0, 0) is in the center of the screen."), - 'setxy2': _("moves turtle to position xcor, ycor; (0, 0) is in the center of the screen."), - 'shade': _("holds current pen shade"), - 'show': _("draws text or show media from the Journal"), - 'showblocks': _("restores hidden blocks"), - 'skin': _("put a custom 'shell' on the turtle"), - 'sqrt': _("calculates square root"), - 'stack1': _("invokes Action 1 stack"), - 'stack2': _("invokes Action 2 stack"), - 'stack': _("invokes named action stack"), - 'start': _("connects action to toolbar run buttons"), - 'startfill': _("starts filled polygon (used with end fill block)"), - 'stopfill': _("completes filled polygon (used with start fill block)"), 'stopiton': _("Stop turtle"), - 'stopstack': _("stops current action"), - 'storeinbox1': _("stores numeric value in Variable 1"), - 'storeinbox2': _("stores numeric value in Variable 2"), - 'storein': _("stores numeric value in named variable"), - 'string': _("string value"), - 'template1x1': _( - "presentation template: select Journal object (with description)"), - 'template1x1a': _( - "presentation template: select Journal object (no description)"), - 'template1x2': _("presentation template: select two Journal objects"), - 'template2x1': _("presentation template: select two Journal objects"), - 'template2x2': _("presentation template: select four Journal objects"), - 'templatelist': _("presentation template: list of bullets"), 'textcolor': _( "holds current text color (can be used in place of a number block)"), 'textsize': _( - "holds current text size (can be used in place of a number block)"), - 'time': _("elapsed time (in seconds) since program started"), - 'toppos': _("ycor of top of screen"), - 'trash': _("Trashcan"), - 'turtle': _("Palette of turtle commands"), - 'until': _("do-until-True operator that uses boolean operators from Numbers palette"), - 'userdefined': _( - "runs code found in the tamyblock.py module found in the Journal"), - 'userdefined2args': _( - "runs code found in the tamyblock.py module found in the Journal"), - 'userdefined3args': _( - "runs code found in the tamyblock.py module found in the Journal"), - 'video': _("Sugar Journal video object"), - 'voltage': _("sensor voltage"), - 'vspace': _("jogs stack down"), - 'wait': _("pauses program execution a specified number of seconds"), - 'while': _("do-while-True operator that uses boolean operators from Numbers palette"), - 'width': _("the canvas width"), - 'xcor': _("holds current x-coordinate value of the turtle (can be used in place of a number block)"), - 'ycor': _("holds current y-coordinate value of the turtle (can be used in place of a number block)")} + "holds current text size (can be used in place of a number block)")} # # 'dead key' Unicode dictionaries diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index 8674fb3..4092536 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -36,9 +36,8 @@ try: except ImportError: pass -from taconstants import TAB_LAYER, BLACK, WHITE, DEFAULT_SCALE, ICON_SIZE, \ - BLOCK_NAMES, CONSTANTS, PREFIX_DICTIONARY -from tajail import myfunc, myfunc_import +from taconstants import TAB_LAYER, DEFAULT_SCALE, BLOCK_NAMES, \ + PREFIX_DICTIONARY, CONSTANTS, BLACK, WHITE from tautils import get_pixbuf_from_journal, convert, data_from_file, \ text_media_type, round_int, chr_to_ord, strtype, get_path, debug_output @@ -46,8 +45,7 @@ from util.RtfParser import RtfTextOnly from gettext import gettext as _ -VALUE_BLOCKS = ['box1', 'box2', 'color', 'shade', 'gray', 'scale', 'pensize', - 'heading', 'xcor', 'ycor', 'pop', 'time', 'keyboard', 'see'] +VALUE_BLOCKS = [] MEDIA_BLOCKS_DICTIONARY = {} # new media blocks get added here PLUGIN_DICTIONARY = {} # new block primitives get added here @@ -81,184 +79,6 @@ class logoerror(Exception): # Utility functions - -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 _string_to_num(x): - """ Try to comvert a string to a number """ - 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 _and(x, y): - """ Logical and """ - return x & y - - -def _or(x, y): - """ Logical or """ - return x | y - - -def _careful_divide(x, y): - """ Raise error on divide by zero """ - try: - return x / y - except ZeroDivisionError: - raise logoerror("#zerodivide") - except TypeError: - try: - return _string_to_num(x) / _string_to_num(y) - except ZeroDivisionError: - raise logoerror("#zerodivide") - except ValueError: - raise logoerror("#syntaxerror") - except TypeError: - raise logoerror("#notanumber") - - -def _equal(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 _string_to_num(x) == _string_to_num(y) - except ValueError: - raise logoerror("#syntaxerror") - - -def _less(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 _string_to_num(x) < _string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - -def _more(x, y): - """ Compare numbers and strings """ - return _less(y, x) - - -def _plus(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 _minus(x, y): - """ Numerical subtraction """ - if _num_type(x) and _num_type(y): - return(x - y) - try: - return _string_to_num(x) - _string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - -def _product(x, y): - """ Numerical multiplication """ - if _num_type(x) and _num_type(y): - return(x * y) - try: - return _string_to_num(x) * _string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - - -def _mod(x, y): - """ Numerical mod """ - if _num_type(x) and _num_type(y): - return(x % y) - try: - return _string_to_num(x) % _string_to_num(y) - except TypeError: - raise logoerror("#notanumber") - except ValueError: - raise logoerror("#syntaxerror") - - -def _sqrt(x): - """ Square root """ - if _num_type(x): - if x < 0: - raise logoerror("#negroot") - return sqrt(x) - try: - return sqrt(_string_to_num(x)) - except ValueError: - raise logoerror("#negroot") - except TypeError: - raise logoerror("#notanumber") - - -def _random(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 = _string_to_num(x) - if not yflag: - yy = _string_to_num(y) - try: - return(int(round(uniform(xx, yy), 0))) - except TypeError: - raise logoerror("#notanumber") - - -def _identity(x): - """ Identity function """ - return(x) - - def _just_stop(): """ yield False to stop stack """ yield False @@ -280,149 +100,17 @@ class LogoCode: # TODO: remove plugin blocks DEFPRIM = { '(': [1, lambda self, x: self._prim_opar(x)], - 'and': [2, lambda self, x, y: _and(x, y)], - 'arc': [2, lambda self, x, y: self._prim_arc(self.tw.canvas.arc, x, - y)], - 'audio': [1, lambda self, x: self._play_sound(x)], - 'back': [1, lambda self, x: self._prim_move(self.tw.canvas.forward, - -x)], - 'black': [0, lambda self: BLACK], - 'blue': [0, lambda self: CONSTANTS['blue']], - 'bpos': [0, lambda self: CONSTANTS['bottompos']], - 'boty': [0, lambda self: CONSTANTS['bottomy']], - 'box1': [0, lambda self: self.boxes['box1']], - 'box': [1, lambda self, x: self._box(x)], - 'box2': [0, lambda self: self.boxes['box2']], 'bullet': [1, self._prim_bullet, True], 'bulletlist': [1, self._prim_list, True], - 'cartesian': [0, lambda self: self.tw.set_cartesian(True)], - 'clean': [0, lambda self: self.prim_clear()], - 'clearheap': [0, lambda self: self._empty_heap()], - 'color': [0, lambda self: self.tw.canvas.color], - 'gray': [0, lambda self: self.tw.canvas.gray], - 'comment': [1, lambda self, x: self._prim_print(x, True)], 'container': [1, lambda self, x: x], - 'cyan': [0, lambda self: CONSTANTS['cyan']], 'define': [2, self._prim_define], - 'division': [2, lambda self, x, y: _careful_divide(x, y)], - 'equal?': [2, lambda self, x, y: _equal(x, y)], - 'fillscreen': [2, lambda self, x, y: self.tw.canvas.fillscreen(x, y)], - 'forever': [1, self._prim_forever, True], - 'forward': [1, lambda self, x: self._prim_move(self.tw.canvas.forward, - x)], - 'fullscreen': [0, lambda self: self.tw.set_fullscreen()], - 'greater?': [2, lambda self, x, y: _more(x, y)], - 'green': [0, lambda self: CONSTANTS['green']], - 'heading': [0, lambda self: self.tw.canvas.heading], - 'hideblocks': [0, lambda self: self.tw.hideblocks()], - 'hres': [0, lambda self: CONSTANTS['width']], - 'id': [1, lambda self, x: _identity(x)], - 'if': [2, self._prim_if, True], - 'ifelse': [3, self._prim_ifelse, True], 'insertimage': [1, lambda self, x: self._insert_image(False, filepath=x)], - 'kbinput': [0, lambda self: self._prim_kbinput()], - 'keyboard': [0, lambda self: self.keyboard], - 'left': [1, lambda self, x: self._prim_right(-x)], - 'leftx': [0, lambda self: CONSTANTS['leftx']], - 'lpos': [0, lambda self: CONSTANTS['leftpos']], - 'less?': [2, lambda self, x, y: _less(x, y)], - 'mediawait': [0, self._media_wait, True], - 'minus': [2, lambda self, x, y: _minus(x, y)], - 'mod': [2, lambda self, x, y: _mod(x, y)], - 'myfunction': [2, lambda self, f, x: self._myfunction(f, [x])], - 'myfunction2': [3, lambda self, f, x, y: self._myfunction(f, [x, y])], - 'myfunction3': [4, lambda self, f, x, y, z: self._myfunction( - f, [x, y, z])], 'nop': [0, lambda self: None], - 'nop1': [0, lambda self: None], - 'nop2': [0, lambda self: None], - 'nop3': [1, lambda self, x: None], - 'not': [1, lambda self, x: not x], - 'orange': [0, lambda self: CONSTANTS['orange']], - 'or': [2, lambda self, x, y: _or(x, y)], - 'pendown': [0, lambda self: self.tw.canvas.setpen(True)], - 'pensize': [0, lambda self: self.tw.canvas.pensize], - 'penup': [0, lambda self: self.tw.canvas.setpen(False)], - 'plus': [2, lambda self, x, y: _plus(x, y)], - 'polar': [0, lambda self: self.tw.set_polar(True)], - 'pop': [0, lambda self: self._prim_pop()], - 'print': [1, lambda self, x: self._prim_print(x, False)], - 'printheap': [0, lambda self: self._prim_print_heap()], - 'product': [2, lambda self, x, y: _product(x, y)], - 'purple': [0, lambda self: CONSTANTS['purple']], - 'push': [1, lambda self, x: self._prim_push(x)], - 'random': [2, lambda self, x, y: _random(x, y)], - 'readpixel': [0, lambda self: self._read_pixel()], - 'red': [0, lambda self: CONSTANTS['red']], - 'repeat': [2, self._prim_repeat, True], - 'right': [1, lambda self, x: self._prim_right(x)], - 'rightx': [0, lambda self: CONSTANTS['rightx']], - 'rpos': [0, lambda self: CONSTANTS['rightpos']], - 'savepix': [1, lambda self, x: self._save_picture(x)], - 'savesvg': [1, lambda self, x: self._save_svg(x)], - 'scale': [0, lambda self: self.scale], - 'see': [0, lambda self: self.see()], - 'setcolor': [1, lambda self, x: self._prim_set('color', - self.tw.canvas.setcolor, x)], - 'setgray': [1, lambda self, x: self._prim_set('gray', - self.tw.canvas.setgray, x)], - 'seth': [1, lambda self, x: self._prim_set('heading', - self.tw.canvas.seth, x)], - 'setpensize': [1, lambda self, x: self._prim_set('pensize', - self.tw.canvas.setpensize, x)], - 'setscale': [1, lambda self, x: self._prim_set('scale', - self._set_scale, x)], - 'setshade': [1, lambda self, x: self._prim_set('shade', - self.tw.canvas.setshade, x)], 'settextcolor': [1, lambda self, x: self.tw.canvas.settextcolor(x)], 'settextsize': [1, lambda self, x: self.tw.canvas.settextsize(x)], - 'setxy2': [2, lambda self, x, y: self._prim_move(self.tw.canvas.setxy, - x, y)], - 'setxy': [2, lambda self, x, y: self._prim_move(self.tw.canvas.setxy, - x, y, pendown=False)], - 'shade': [0, lambda self: self.tw.canvas.shade], - 'show': [1, lambda self, x: self._show(x, True)], - 'showaligned': [1, lambda self, x: self._show(x, False)], - 'showblocks': [0, lambda self: self.tw.showblocks()], - 'skin': [1, lambda self, x: self._reskin(x)], - 'sqrt': [1, lambda self, x: _sqrt(x)], - 'stack1': [0, self._prim_stack1, True], - 'stack': [1, self._prim_stack, True], - 'stack2': [0, self._prim_stack2, True], - 'start': [0, lambda self: self._prim_start()], - 'startfill': [0, lambda self: self.tw.canvas.start_fill()], - 'stopfill': [0, lambda self: self.tw.canvas.stop_fill()], - 'stopstack': [0, lambda self: self._prim_stopstack()], - 'storeinbox1': [1, lambda self, x: self._prim_setbox('box1', None, x)], - 'storeinbox2': [1, lambda self, x: self._prim_setbox('box2', None, x)], - 'storeinbox': [2, lambda self, x, y: self._prim_setbox('box3', x, y)], - 't1x1': [2, lambda self, x, y: self._show_template1x1(x, y)], - 't1x1a': [2, lambda self, x, y: self._show_template1x1a(x, y)], - 't1x2': [3, lambda self, x, y, z: self._show_template1x2(x, y, z)], - 't2x1': [3, lambda self, x, y, z: self._show_template2x1(x, y, z)], - 't2x2': [5, lambda self, x, y, z, a, b: self._show_template2x2( - x, y, z, a, b)], 'textcolor': [0, lambda self: self.tw.canvas.textcolor], - 'textsize': [0, lambda self: self.tw.textsize], - 'time': [0, lambda self: self._elapsed_time()], - 'titlex': [0, lambda self: CONSTANTS['titlex']], - 'titley': [0, lambda self: CONSTANTS['titley']], - 'topy': [0, lambda self: CONSTANTS['topy']], - 'tpos': [0, lambda self: CONSTANTS['toppos']], - 'turtle': [1, lambda self, x: self.tw.canvas.set_turtle(x)], - 'userdefined': [1, lambda self, x: self._prim_myblock([x])], - 'userdefined2': [2, lambda self, x, y: self._prim_myblock([x, y])], - 'userdefined3': [3, lambda self, x, y, - z: self._prim_myblock([x, y, z])], - 'video': [1, lambda self, x: self._play_video(x)], - 'vres': [0, lambda self: CONSTANTS['height']], - 'wait': [1, self._prim_wait, True], - 'white': [0, lambda self: WHITE], - 'write': [2, lambda self, x, y: self._write(self, x, y)], - 'xcor': [0, lambda self: self.tw.canvas.xcor / self.tw.coord_scale], - 'ycor': [0, lambda self: self.tw.canvas.ycor / self.tw.coord_scale], - 'yellow': [0, lambda self: CONSTANTS['yellow']]} + 'textsize': [0, lambda self: self.tw.textsize]} for p in iter(DEFPRIM): if len(DEFPRIM[p]) == 2: @@ -811,47 +499,6 @@ class LogoCode: # Primitives # - def prim_clear(self): - """ Clear screen """ - if self.tw.gst_available: - from tagplay import stop_media - stop_media(self) - self.tw.canvas.clearscreen() - self.scale = DEFAULT_SCALE - # Note: users find this "feature" confusing - # self.tw.set_polar(False) - # self.tw.set_cartesian(False) - self.hidden_turtle = None - self._start_time = time() - for name in VALUE_BLOCKS: - self.update_label_value(name) - - def _prim_start(self): - """ Start block: recenter """ - if self.tw.running_sugar: - self.tw.activity.recenter() - - 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._ireturn() - yield True - - def _prim_repeat(self, num, blklist): - """ Repeat list num times. """ - num = self._int(num) - for i in range(num): - self._icall(self._evline, blklist[:]) - yield True - if self.procstop: - break - self._ireturn() - yield True - def _prim_bullet(self, blklist): """ Depreciated bullet-list block style """ self._show_bullets(blklist) @@ -864,75 +511,6 @@ class LogoCode: self._ireturn() yield True - def _myfunction(self, f, x): - """ Programmable block """ - try: - y = myfunc(f, x) - if str(y) == 'nan': - debug_output('Python function returned NAN', - self.tw.running_sugar) - self.stop_logo() - raise logoerror("#notanumber") - else: - return y - except ZeroDivisionError: - self.stop_logo() - raise logoerror("#zerodivide") - except ValueError, e: - self.stop_logo() - raise logoerror('#' + str(e)) - except SyntaxError, e: - self.stop_logo() - raise logoerror('#' + str(e)) - except NameError, e: - self.stop_logo() - raise logoerror('#' + str(e)) - except OverflowError: - self.stop_logo() - raise logoerror("#overflowerror") - except TypeError: - self.stop_logo() - raise logoerror("#notanumber") - - def _prim_forever(self, blklist): - """ Do list forever """ - while True: - self._icall(self._evline, blklist[:]) - yield True - if self.procstop: - break - self._ireturn() - yield True - - ''' - def _prim_while(self, list1, list2): - list = [self._intern('if')] - for i in list1: - list.append(i) - list.append(list2) - while self._icall(self._evline, list[:]): - yield True - self._ireturn() - yield True - ''' - - def _prim_if(self, boolean, blklist): - """ If bool, do list """ - if boolean: - self._icall(self._evline, blklist[:]) - yield True - self._ireturn() - yield True - - def _prim_ifelse(self, boolean, list1, list2): - """ If bool, do list1, else do list2 """ - if boolean: - self._ijmp(self._evline, list1[:]) - yield True - else: - self._ijmp(self._evline, list2[:]) - yield True - def _prim_opar(self, val): self.iline.pop(0) return val @@ -978,14 +556,6 @@ class LogoCode: self._ireturn() yield True - def _prim_stopstack(self): - """ Stop execution of a stack """ - self.procstop = True - - def _prim_print_heap(self): - """ Display contents of heap """ - self.tw.showlabel('status', str(self.heap) + ' ') - def _int(self, n): """ Raise an error if n doesn't convert to int. """ if type(n) == int: @@ -998,68 +568,6 @@ class LogoCode: raise logoerror("%s %s %s %s" \ % (self.cfun.name, _("doesn't like"), str(n), _("as input"))) - def _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.boxes['box3' + str(x)] - except KeyError: - raise logoerror("#emptybox") - - def _prim_myblock(self, x): - """ Run Python code imported from Journal """ - if self.bindex is not None and self.bindex in self.tw.myblock: - try: - if len(x) == 1: - myfunc_import(self, self.tw.myblock[self.bindex], x[0]) - else: - myfunc_import(self, self.tw.myblock[self.bindex], x) - except: - raise logoerror("#syntaxerror") - - def _prim_print(self, n, flag): - """ Print object n """ - if flag and (self.tw.hide or self.tw.step_time == 0): - return - if type(n) == str or type(n) == unicode: - if n[0:6] == 'media_' and \ - n[6:].lower not in MEDIA_BLOCKS_DICTIONARY: - try: - if self.tw.running_sugar: - try: - dsobject = datastore.get(n[6:]) - except: - debug_output("Couldn't open %s" % (n[6:]), - self.tw.running_sugar) - self.tw.showlabel('status', dsobject.metadata['title']) - dsobject.destroy() - else: - self.tw.showlabel('status', n[6:]) - except IOError: - self.tw.showlabel('status', n) - else: - self.tw.showlabel('status', n) - elif type(n) == int: - self.tw.showlabel('status', n) - else: - self.tw.showlabel('status', - str(round_int(n)).replace('.', self.tw.decimal_point)) - - def _prim_kbinput(self): - """ Query keyboard """ - if len(self.tw.keypress) == 1: - self.keyboard = ord(self.tw.keypress[0]) - else: - try: - self.keyboard = {'Escape': 27, 'space': 32, ' ': 32, - 'Return': 13, 'KP_Up': 2, 'KP_Down': 4, - 'KP_Left': 1, 'KP_Right': 3}[self.tw.keypress] - except KeyError: - self.keyboard = 0 - self.update_label_value('keyboard', self.keyboard) - self.tw.keypress = '' def find_value_blocks(self): """ Find any value blocks that may need label updates """ @@ -1087,69 +595,6 @@ class LogoCode: block.spr.set_label(BLOCK_NAMES[name][0] + ' = ' + valstring) block.resize() - 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.update_label_value(name, value) - - def _prim_right(self, value): - """ Turtle rotates clockwise """ - self.tw.canvas.right(float(value)) - self.update_label_value('heading', self.tw.canvas.heading) - - 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.update_label_value('xcor', - self.tw.canvas.xcor / self.tw.coord_scale) - self.update_label_value('ycor', - self.tw.canvas.ycor / self.tw.coord_scale) - if len(self.value_blocks['see']) > 0: - self.see() - - def _prim_arc(self, cmd, value1, value2): - """ Turtle draws an arc of degree, radius """ - cmd(float(value1), float(value2)) - self.update_label_value('xcor', - self.tw.canvas.xcor / self.tw.coord_scale) - self.update_label_value('ycor', - self.tw.canvas.ycor / self.tw.coord_scale) - self.update_label_value('heading', self.tw.canvas.heading) - if len(self.value_blocks['see']) > 0: - self.see() - - 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.boxes[name + str(x)] = val - return - - self.boxes[name] = val - self.update_label_value(name, val) - - def _prim_push(self, val): - """ Push value onto FILO """ - self.heap.append(val) - self.update_label_value('pop', val) - - def _prim_pop(self): - """ Pop value off of FILO """ - if len(self.heap) == 0: - raise logoerror("#emptyheap") - else: - if len(self.heap) == 1: - self.update_label_value('pop') - else: - self.update_label_value('pop', self.heap[-2]) - return self.heap.pop(-1) - def push_file_data_to_heap(self, dsobject): """ push contents of a data store object (assuming json encoding) """ data = data_from_file(dsobject.file_path) @@ -1158,19 +603,6 @@ class LogoCode: self.heap.append(val) self.update_label_value('pop', self.heap[-1]) - def _empty_heap(self): - """ Empty FILO """ - self.heap = [] - - def _save_picture(self, name): - """ Save canvas to file as PNG """ - self.tw.save_as_image(name) - - def _save_svg(self, name): - """ Save SVG to file """ - self.tw.canvas.svg_close() - self.tw.save_as_image(name, True) - def _show_list(self, sarray): """ Display list of media objects """ x = self.tw.canvas.xcor / self.tw.coord_scale @@ -1180,47 +612,6 @@ class LogoCode: self._show(s) y -= int(self.tw.canvas.textsize * self.tw.lead) - def _set_scale(self, x): - """ Set scale used by media object display """ - self.scale = x - - def _reskin(self, media): - """ Reskin the turtle with an image from a file """ - scale = int(ICON_SIZE * float(self.scale) / DEFAULT_SCALE) - if scale < 1: - return - self.filepath = None - dsobject = None - if os.path.exists(media[6:]): # is it a path? - self.filepath = media[6:] - elif self.tw.running_sugar: # is it a datastore object? - try: - dsobject = datastore.get(media[6:]) - except: - debug_output("Couldn't open skin %s" % (media[6:]), - self.tw.running_sugar) - if dsobject is not None: - self.filepath = dsobject.file_path - if self.filepath == None: - self.tw.showlabel('nojournal', self.filepath) - return - pixbuf = None - try: - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.filepath, scale, - scale) - except: - self.tw.showlabel('nojournal', self.filepath) - debug_output("Couldn't open skin %s" % (self.filepath), - self.tw.running_sugar) - if pixbuf is not None: - self.tw.active_turtle.set_shapes([pixbuf]) - pen_state = self.tw.active_turtle.get_pen_state() - if pen_state: - self.tw.canvas.setpen(False) - self.tw.canvas.forward(0) - if pen_state: - self.tw.canvas.setpen(True) - def _x(self): """ Convert screen coordinates to turtle coordinates """ return int(self.tw.canvas.width / 2) + int(self.tw.canvas.xcor) @@ -1237,73 +628,6 @@ class LogoCode: """ Convert screen coordinates to turtle coordinates """ return int((self.tw.canvas.height * self.scale) / 100.) - def _show(self, string, center=False): - """ Show is the general-purpose media-rendering block. """ - if type(string) == str or type(string) == unicode: - if string in ['media_', 'descr_', 'audio_', 'video_', - 'media_None', 'descr_None', 'audio_None', - 'video_None']: - pass - elif string[0:6] in ['media_', 'descr_', 'audio_', 'video_']: - self.filepath = None - self.dsobject = None - print string[6:], MEDIA_BLOCKS_DICTIONARY - if string[6:].lower() in MEDIA_BLOCKS_DICTIONARY: - MEDIA_BLOCKS_DICTIONARY[string[6:].lower()]() - elif os.path.exists(string[6:]): # is it a path? - self.filepath = string[6:] - elif self.tw.running_sugar: # is it a datastore object? - try: - self.dsobject = datastore.get(string[6:]) - except: - debug_output("Couldn't find dsobject %s" % ( - string[6:]), self.tw.running_sugar) - if self.dsobject is not None: - self.filepath = self.dsobject.file_path - if self.filepath == None: - if self.dsobject is not None: - self.tw.showlabel('nojournal', - self.dsobject.metadata['title']) - else: - self.tw.showlabel('nojournal', string[6:]) - debug_output("Couldn't open %s" % (string[6:]), - self.tw.running_sugar) - elif string[0:6] == 'media_': - self._insert_image(center) - elif string[0:6] == 'descr_': - mimetype = None - if self.dsobject is not None and \ - 'mime_type' in self.dsobject.metadata: - mimetype = self.dsobject.metadata['mime_type'] - description = None - if self.dsobject is not None and \ - 'description' in self.dsobject.metadata: - description = self.dsobject.metadata['description'] - self._insert_desc(mimetype, description) - elif string[0:6] == 'audio_': - self._play_sound() - elif string[0:6] == 'video_': - self._play_video() - if self.dsobject is not None: - self.dsobject.destroy() - else: # assume it is text to display - x, y = self._x(), self._y() - if center: - y -= self.tw.canvas.textsize - self.tw.canvas.draw_text(string, x, y, - int(self.tw.canvas.textsize * \ - self.scale / 100.), - self.tw.canvas.width - x) - elif type(string) == float or type(string) == int: - string = round_int(string) - x, y = self._x(), self._y() - if center: - y -= self.tw.canvas.textsize - self.tw.canvas.draw_text(string, x, y, - int(self.tw.canvas.textsize * \ - self.scale / 100.), - self.tw.canvas.width - x) - def _insert_image(self, center=False, filepath=None): """ Image only (at current x, y) """ if filepath is not None: @@ -1393,213 +717,3 @@ class LogoCode: from tagplay import play_movie_from_file play_movie_from_file(self, self.filepath, self._x(), self._y(), w, h) - - def _elapsed_time(self): - """ Number of seconds since program execution has started or - clean (prim_clear) block encountered """ - elapsed_time = int(time() - self._start_time) - self.update_label_value('time', elapsed_time) - return elapsed_time - - def see(self): - """ Read r, g, b from the canvas and return a corresponding palette - color """ - r, g, b, a = self.tw.canvas.get_pixel() - color_index = self.tw.canvas.get_color_index(r, g, b) - self.update_label_value('see', color_index) - return color_index - - def _read_pixel(self): - """ Read r, g, b, a from the canvas and push b, g, r to the stack """ - r, g, b, a = self.tw.canvas.get_pixel() - self.heap.append(b) - self.heap.append(g) - self.heap.append(r) - # Depreciated block methods - - def _show_template1x1(self, title, media): - """ title, one image, and description """ - xo = self.tw.calc_position('t1x1')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height * 2) \ - / self.tw.canvas.height - self._set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render media object - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media) - if self.tw.running_sugar: - x = 0 - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media.replace('media_', 'descr_')) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _show_template2x1(self, title, media1, media2): - """ title, two images (horizontal), two descriptions """ - xo = self.tw.calc_position('t2x1')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ - self.tw.canvas.height - self._set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1) - x = 0 - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media2) - y = -self.title_height - if self.tw.running_sugar: - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media2.replace('media_', 'descr_')) - x = -(self.tw.canvas.width / 2) + xo - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1.replace('media_', 'descr_')) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _show_bullets(self, sarray): - """ title and varible number of bullets """ - xo = self.tw.calc_position('bullet')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(sarray[0]) - # set body text size - self.tw.canvas.settextsize(self.bullet_height) - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - for s in sarray[1:]: - self.tw.canvas.setxy(x, y, pendown=False) - self._show(s) - y -= int(self.bullet_height * 2 * self.tw.lead) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _show_template1x2(self, title, media1, media2): - """ title, two images (vertical), two desciptions """ - xo = self.tw.calc_position('t1x2')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ - self.tw.canvas.height - self._set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1) - if self.tw.running_sugar: - x = 0 - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1.replace('media_', 'descr_')) - y = -self.title_height - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media2.replace('media_', 'descr_')) - x = -(self.tw.canvas.width / 2) + xo - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media2) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _show_template2x2(self, title, media1, media2, media3, media4): - """ title and four images """ - xo = self.tw.calc_position('t2x2')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(title) - # calculate and set scale for media blocks - myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ - self.tw.canvas.height - self._set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render four quadrents - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1) - x = 0 - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media2) - y = -self.title_height - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media4) - x = -(self.tw.canvas.width / 2) + xo - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media3) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _show_template1x1a(self, title, media1): - """ title, one media object """ - xo = self.tw.calc_position('t1x1a')[2] - x = -(self.tw.canvas.width / 2) + xo - y = self.tw.canvas.height / 2 - self.tw.canvas.setxy(x, y, pendown=False) - # save the text size so we can restore it later - save_text_size = self.tw.canvas.textsize - # set title text - self.tw.canvas.settextsize(self.title_height) - self._show(title) - # calculate and set scale for media blocks - myscale = 90 * (self.tw.canvas.height - self.title_height * 2) / \ - self.tw.canvas.height - self._set_scale(myscale) - # set body text size - self.tw.canvas.settextsize(self.body_height) - # render media object - # leave some space below the title - y -= int(self.title_height * 2 * self.tw.lead) - self.tw.canvas.setxy(x, y, pendown=False) - self._show(media1) - # restore text size - self.tw.canvas.settextsize(save_text_size) - - def _write(self, string, fsize): - """ Write string at size """ - x = self.tw.canvas.width / 2 + int(self.tw.canvas.xcor) - y = self.tw.canvas.height / 2 - int(self.tw.canvas.ycor) - self.tw.canvas.draw_text(string, x, y - 15, int(fsize), - self.tw.canvas.width) diff --git a/TurtleArt/taprimitive.py b/TurtleArt/taprimitive.py index 4be5172..75a1efd 100644 --- a/TurtleArt/taprimitive.py +++ b/TurtleArt/taprimitive.py @@ -21,7 +21,7 @@ from taconstants import BLOCK_STYLES, BLOCK_NAMES, HELP_STRINGS, PALETTES, \ PALETTE_NAMES, CONTENT_BLOCKS, PRIMITIVES, DEFAULTS, SPECIAL_NAMES, \ - COLORS + COLORS, EXPANDABLE_STYLE, EXPANDABLE_BLOCKS from talogo import VALUE_BLOCKS from tautils import debug_output @@ -29,12 +29,13 @@ from tautils import debug_output class Palette(): """ a class for defining new palettes """ - def __init__(self, name, colors=["#00FF00", "#00A000"]): + def __init__(self, name, colors=["#00FF00", "#00A000"], position=None): self._name = name + self._special_name = name self._colors = colors self._help = None - def add_palette(self): + def add_palette(self, position=None): if self._name is None: debug_output('You must specify a name for your palette') return @@ -44,12 +45,20 @@ class Palette(): i = PALETTE_NAMES.index('trash') else: i = len(PALETTE_NAMES) - PALETTE_NAMES.insert(i, self._name) - PALETTES.insert(i, []) - COLORS.insert(i, self._colors) + + if position is not None and type(position) is int and position < i: + i = position + + if self._name not in PALETTE_NAMES: + PALETTE_NAMES.insert(i, self._name) + PALETTES.insert(i, []) + COLORS.insert(i, self._colors) + else: + # debug_output('Palette %s already defined' % (self._name)) + return # Special name entry is needed for help hover mechanism - SPECIAL_NAMES[self._name] = self._name + SPECIAL_NAMES[self._name] = self._special_name if self._help is not None: HELP_STRINGS[self._name] = self._help else: @@ -58,6 +67,8 @@ class Palette(): def set_help(self, help): self._help = help + def set_special_name(self, name): + self._special_name = name class Primitive(): """ a class for defining new block primitives """ @@ -74,7 +85,7 @@ class Primitive(): self._value_block = False self._content_block = False - def add_prim(self): + def add_prim(self, position=None): if self._name is None: debug_output('You must specify a name for your block') return @@ -89,7 +100,14 @@ class Primitive(): BLOCK_NAMES[self._name] = self._label if self._palette is not None: - PALETTES[PALETTE_NAMES.index(self._palette)].append(self._name) + i = PALETTE_NAMES.index(self._palette) + if position is not None and type(position) is int and \ + position < len(PALETTES[i]): + PALETTES[i].insert(position, self._name) + else: + PALETTES[i].append(self._name) + if position is not None: + debug_output('Ignoring position (%s)' % (str(position))) if self._help is not None: HELP_STRINGS[self._name] = self._help @@ -111,6 +129,9 @@ class Primitive(): if self._special_name is not None: SPECIAL_NAMES[self._name] = self._special_name + if self._style in EXPANDABLE_STYLE: + EXPANDABLE_BLOCKS.append(self._name) + def set_value_block(self, value=True): self._value_block = value diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 42a3a5d..e35b8f7 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -196,7 +196,6 @@ class TurtleArtWindow(): self.palette_sprs = [] self.palettes = [] self.palette_button = [] - self.trash_index = PALETTE_NAMES.index('trash') self.trash_stack = [] self.selected_palette = None self.previous_palette = None @@ -256,6 +255,9 @@ class TurtleArtWindow(): self._init_plugins() self.lc = LogoCode(self) + + from tabasics import Palettes + p = Palettes(self) self._setup_plugins() if self.interactive_mode: @@ -713,7 +715,7 @@ class TurtleArtWindow(): self._layout_palette(n) for blk in self.palettes[n]: blk.spr.set_layer(TAB_LAYER) - if n == self.trash_index: + if n == PALETTE_NAMES.index('trash'): for blk in self.trash_stack: for gblk in find_group(blk): if gblk.status != 'collapsed': @@ -721,6 +723,8 @@ class TurtleArtWindow(): def _hide_toolbar_palette(self): """ Hide the toolbar palettes """ + print self.activity.palette_buttons + print self.selected_palette self._hide_previous_palette() if self.activity is None or not self.activity.new_sugar_system: # Hide the selectors @@ -747,7 +751,7 @@ class TurtleArtWindow(): self.previous_palette != self.selected_palette: self.activity.palette_buttons[self.previous_palette].set_icon( PALETTE_NAMES[self.previous_palette] + 'off') - if self.previous_palette == self.trash_index: + if self.previous_palette == PALETTE_NAMES.index('trash'): for blk in self.trash_stack: for gblk in find_group(blk): gblk.spr.hide() @@ -813,7 +817,7 @@ class TurtleArtWindow(): _x, _y = 20, self.toolbar_offset + 5 _x, _y, _max = self._horizontal_layout(_x, _y, self.palettes[n]) - if n == self.trash_index: + if n == PALETTE_NAMES.index('trash'): _x, _y, _max = self._horizontal_layout(_x + _max, _y, self.trash_stack) _w = _x + _max + 25 @@ -1038,8 +1042,8 @@ class TurtleArtWindow(): if gblk.name in BLOCKS_WITH_SKIN: self._resize_skin(gblk) - # self.show_palette(self.trash_index) - if self.selected_palette != self.trash_index: + # self.show_palette(PALETTE_NAMES.index('trash')) + if self.selected_palette != PALETTE_NAMES.index('trash'): for gblk in group: gblk.spr.hide() @@ -1091,8 +1095,8 @@ class TurtleArtWindow(): def _in_the_trash(self, x, y): """ Is x, y over the trash can? """ """ - if self.selected_palette == self.trash_index and \ - self.palette_sprs[self.trash_index][self.orientation].hit((x, y)): + if self.selected_palette == PALETTE_NAMES.index('trash') and \ + self.palette_sprs[PALETTE_NAMES.index('trash')][self.orientation].hit((x, y)): return True """ if self.selected_palette is not None and \ diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py index aa8d5bd..5087c53 100644 --- a/TurtleArtActivity.py +++ b/TurtleArtActivity.py @@ -71,6 +71,7 @@ class TurtleArtActivity(activity.Activity): self._check_ver_change(datapath) self._setup_canvas(canvas) + self._setup_palette_toolbar() self._setup_sharing() @@ -448,7 +449,7 @@ class TurtleArtActivity(activity.Activity): if self.new_sugar_system: # Use 0.86 toolbar design # Create toolbox and secondary toolbars - toolbox = ToolbarBox() + self._toolbox = ToolbarBox() activity_toolbar_button = ActivityToolbarButton(self) @@ -460,9 +461,9 @@ class TurtleArtActivity(activity.Activity): view_toolbar_button = ToolbarButton(label=_('View'), page=view_toolbar, icon_name='toolbar-view') - palette_toolbar = gtk.Toolbar() - palette_toolbar_button = ToolbarButton(page=palette_toolbar, - icon_name='palette') + self._palette_toolbar = gtk.Toolbar() + self._palette_toolbar_button = ToolbarButton( + page=self._palette_toolbar, icon_name='palette') help_toolbar = gtk.Toolbar() help_toolbar_button = ToolbarButton(label=_("Help"), page=help_toolbar, @@ -471,50 +472,51 @@ class TurtleArtActivity(activity.Activity): journal_toolbar = gtk.Toolbar() journal_toolbar_button = ToolbarButton(page=journal_toolbar, icon_name='activity-journal') + # Add the toolbars and buttons to the toolbox activity_toolbar_button.show() - toolbox.toolbar.insert(activity_toolbar_button, -1) + self._toolbox.toolbar.insert(activity_toolbar_button, -1) edit_toolbar_button.show() - toolbox.toolbar.insert(edit_toolbar_button, -1) + self._toolbox.toolbar.insert(edit_toolbar_button, -1) journal_toolbar_button.show() - toolbox.toolbar.insert(journal_toolbar_button, -1) + self._toolbox.toolbar.insert(journal_toolbar_button, -1) view_toolbar_button.show() - toolbox.toolbar.insert(view_toolbar_button, -1) - palette_toolbar_button.show() - toolbox.toolbar.insert(palette_toolbar_button, -1) + self._toolbox.toolbar.insert(view_toolbar_button, -1) + self._palette_toolbar_button.show() + self._toolbox.toolbar.insert(self._palette_toolbar_button, -1) help_toolbar_button.show() - toolbox.toolbar.insert(help_toolbar_button, -1) + self._toolbox.toolbar.insert(help_toolbar_button, -1) - self._add_separator(toolbox.toolbar) + self._add_separator(self._toolbox.toolbar) - self._make_project_buttons(toolbox.toolbar) + self._make_project_buttons(self._toolbox.toolbar) - self._add_separator(toolbox.toolbar, True) + self._add_separator(self._toolbox.toolbar, True) stop_button = StopButton(self) stop_button.props.accelerator = 'Q' - toolbox.toolbar.insert(stop_button, -1) + self._toolbox.toolbar.insert(stop_button, -1) stop_button.show() else: # Use pre-0.86 toolbar design - toolbox = activity.ActivityToolbox(self) - self.set_toolbox(toolbox) + self._toolbox = activity.ActivityToolbox(self) + self.set_toolbox(self._toolbox) project_toolbar = gtk.Toolbar() - toolbox.add_toolbar(_('Project'), project_toolbar) + self._toolbox.add_toolbar(_('Project'), project_toolbar) view_toolbar = gtk.Toolbar() - toolbox.add_toolbar(_('View'), view_toolbar) + self._toolbox.add_toolbar(_('View'), view_toolbar) view_toolbar_button = view_toolbar edit_toolbar = gtk.Toolbar() - toolbox.add_toolbar(_('Edit'), edit_toolbar) + self._toolbox.add_toolbar(_('Edit'), edit_toolbar) edit_toolbar_button = edit_toolbar journal_toolbar = gtk.Toolbar() - toolbox.add_toolbar(_('Import/Export'), journal_toolbar) + self._toolbox.add_toolbar(_('Import/Export'), journal_toolbar) journal_toolbar_button = journal_toolbar help_toolbar = gtk.Toolbar() - toolbox.add_toolbar(_('Help'), help_toolbar) + self._toolbox.add_toolbar(_('Help'), help_toolbar) help_toolbar_button = help_toolbar self._make_palette_buttons(project_toolbar, palette_button=True) @@ -575,6 +577,24 @@ class TurtleArtActivity(activity.Activity): _("Move the cursor over the orange palette for help."), help_toolbar, gtk.gdk.screen_width() - 2 * ICON_SIZE) + # Setup palette toolbar only AFTER initializing the plugins + # self._setup_palette_toolbar() + + edit_toolbar.show() + view_toolbar.show() + help_toolbar.show() + self._toolbox.show() + + if self.new_sugar_system: + # Hack as a workaround for #2050 + edit_toolbar_button.set_expanded(True) + edit_toolbar_button.set_expanded(False) + + self._palette_toolbar_button.set_expanded(True) + else: + self._toolbox.set_current_toolbar(1) + + def _setup_palette_toolbar(self): # The palette toolbar is only used with 0.86+ if self.new_sugar_system: self.palette_buttons = [] @@ -585,27 +605,14 @@ class TurtleArtActivity(activity.Activity): suffix = 'on' self.palette_buttons.append(self._add_button(name + suffix, HELP_STRINGS[name], self.do_palette_buttons_cb, - palette_toolbar_button, None, i)) - self._add_separator(palette_toolbar, True) - - self._make_palette_buttons(palette_toolbar_button) + self._palette_toolbar_button, None, i)) + self._add_separator(self._palette_toolbar, True) - self.set_toolbar_box(toolbox) - palette_toolbar.show() + self._make_palette_buttons(self._palette_toolbar_button) - edit_toolbar.show() - view_toolbar.show() - help_toolbar.show() - toolbox.show() + self.set_toolbar_box(self._toolbox) + self._palette_toolbar.show() - if self.new_sugar_system: - # Hack as a workaround for #2050 - edit_toolbar_button.set_expanded(True) - edit_toolbar_button.set_expanded(False) - - palette_toolbar_button.set_expanded(True) - else: - toolbox.set_current_toolbar(1) def _make_palette_buttons(self, toolbar, palette_button=False): """ Creates the palette and block buttons for both toolbar types""" diff --git a/plugins/turtle_blocks_plugin.py b/plugins/turtle_blocks_plugin.py new file mode 100644 index 0000000..c7199f2 --- /dev/null +++ b/plugins/turtle_blocks_plugin.py @@ -0,0 +1,1202 @@ +# -*- 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. + +import gtk +from time import time +import os.path +from gettext import gettext as _ + +try: + from sugar.datastore import datastore +except ImportError: + pass + +from plugin import Plugin +from TurtleArt.taprimitive import Palette, Primitive +from TurtleArt.talogo import PLUGIN_DICTIONARY, logoerror, \ + MEDIA_BLOCKS_DICTIONARY +from TurtleArt.taconstants import DEFAULT_SCALE, CONSTANTS, BLACK, WHITE, \ + ICON_SIZE +from TurtleArt.tautils import convert, round_int, debug_output +from TurtleArt.tajail import myfunc, myfunc_import + +# TODO: add expandibles to taprimitives +# fix position problem + + +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 _string_to_num(x): + """ Try to comvert a string to a number """ + 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 _millisecond(): + """ Current time in milliseconds """ + return time() * 1000 + + +class Turtle_blocks_plugin(Plugin): + """ a class for defining the extra palettes that distinguish Turtle Blocks + from Turtle Art """ + + def __init__(self, parent): + self.tw = parent + + def setup(self): + # set up Turtle Block palettes + self._flow_palette() + + p = Palette('media', ["#A0FF00", "#80A000"]) + p.set_help(_('Palette of media objects')) + p.add_palette() + self._media_palette() + + p = Palette('sensor', ["#FF6060", "#A06060"]) + p.set_help(_('Palette of sensor blocks')) + p.add_palette() + self._sensor_palette() + + p = Palette('extras', ["#FF0000", "#A00000"]) + p.set_help(_('Palette of extra options')) + p.add_palette() + self._extras_palette() + + p = Palette('portfolio', ["#0606FF", "#0606A0"]) + p.set_help(_('Palette of presentation templates')) + p.add_palette() + self._portfolio_palette() + + def start(self): + pass + + def stop(self): + pass + + def goto_background(self): + pass + + def return_to_foreground(self): + pass + + def quit(self): + pass + + # Palette definitions + + def _flow_palette(self): + b = Primitive('while') # macro + b.set_palette('flow') + b.set_style('flow-style-boolean') + b.set_label(_('while')) + b.set_help(_('do-while-True operator that uses boolean operators from Numbers palette')) + b.add_prim() + + b = Primitive('until') # macro + b.set_palette('flow') + b.set_style('flow-style-boolean') + b.set_label(_('until')) + b.set_help(_('do-until-True operator that uses boolean operators from Numbers palette')) + b.add_prim() + + def _media_palette(self): + b = Primitive('journal') + b.set_palette('media') + b.set_style('box-style-media') + b.set_label(' ') + b.set_special_name(_('journal')) + b.set_default(None) + b.set_help(_('Sugar Journal media object')) + b.add_prim() + + b = Primitive('audio') + b.set_palette('media') + b.set_style('box-style-media') + b.set_label(' ') + b.set_special_name(_('audio')) + b.set_default(None) + b.set_help(_('Sugar Journal audio object')) + b.add_prim() + + b = Primitive('video') + b.set_palette('media') + b.set_style('box-style-media') + b.set_label(' ') + b.set_special_name(_('video')) + b.set_default(None) + b.set_help(_('Sugar Journal video object')) + b.add_prim() + + b = Primitive('description') + b.set_palette('media') + b.set_style('box-style-media') + b.set_label(' ') + b.set_special_name(_('description')) + b.set_default(None) + b.set_help(_('Sugar Journal description field')) + b.add_prim() + + b = Primitive('string') + b.set_palette('media') + 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('show') + b.set_palette('media') + b.set_style('basic-style-1arg') + b.set_label(_('show')) + b.set_default(_('text')) + b.set_prim_name('show') + b.set_help(_('draws text or show media from the Journal')) + PLUGIN_DICTIONARY['show'] = self._prim_show + self.tw.lc._def_prim('show', 1, + lambda self, x: PLUGIN_DICTIONARY['show'](x, True)) + b.add_prim() + + b = Primitive('showaligned') + b.set_style('basic-style-1arg') + b.set_label(_('show aligned')) + b.set_default(_('text')) + b.set_prim_name('showaligned') + b.set_help(_('draws text or show media from the Journal')) + self.tw.lc._def_prim('showaligned', 1, + lambda self, x: PLUGIN_DICTIONARY['show'](x, False)) + b.add_prim() + + b = Primitive('setscale') + b.set_palette('media') + b.set_style('basic-style-1arg') + b.set_label(_('set scale')) + b.set_prim_name('setscale') + b.set_default(33) + b.set_help(_('sets the scale of media')) + PLUGIN_DICTIONARY['setscale'] = self._prim_setscale + self.tw.lc._def_prim('setscale', 1, + lambda self, x: PLUGIN_DICTIONARY['setscale'](x)) + + b.add_prim() + + b = Primitive('savepix') + b.set_palette('media') + b.set_style('basic-style-1arg') + b.set_label(_('save picture')) + b.set_prim_name('savepix') + b.set_default(_('picture name')) + b.set_help(_('saves a picture to the Sugar Journal')) + PLUGIN_DICTIONARY['savepix'] = self._prim_save_picture + self.tw.lc._def_prim('savepix', 1, + lambda self, x: PLUGIN_DICTIONARY['savepix'](x)) + b.add_prim() + + b = Primitive('savesvg') + b.set_palette('media') + b.set_style('basic-style-1arg') + b.set_label(_('save SVG')) + b.set_prim_name('savesvg') + b.set_default(_('picture name')) + b.set_help(_('saves turtle graphics as an SVG file in the Sugar Journal')) + PLUGIN_DICTIONARY['savesvg'] = self._prim_save_svg + self.tw.lc._def_prim('savesvg', 1, + lambda self, x: PLUGIN_DICTIONARY['savesvg'](x)) + b.add_prim() + + b = Primitive('scale') + b.set_palette('media') + b.set_style('box-style') + b.set_label(_('scale')) + b.set_prim_name('scale') + b.set_value_block(True) + b.set_help(_('holds current scale value')) + self.tw.lc._def_prim('scale', 0, lambda self: self.tw.lc.scale) + b.add_prim() + + b = Primitive('mediawait') + b.set_palette('media') + b.set_style('basic-style-extended-vertical') + b.set_label(_('media wait')) + b.set_prim_name('mediawait') + b.set_help(_('wait for current video or audio to complete')) + self.tw.lc._def_prim('mediawait', 0, self.tw.lc._media_wait, True) + b.add_prim() + + def _sensor_palette(self): + b = Primitive('kbinput') + b.set_palette('sensor') + b.set_style('basic-style-extended-vertical') + b.set_label(_('query keyboard')) + b.set_prim_name('kbinput') + b.set_help(_('query for keyboard input (results stored in keyboard block)')) + PLUGIN_DICTIONARY['kbinput'] = self._prim_kbinput + self.tw.lc._def_prim('kbinput', 0, + lambda self: PLUGIN_DICTIONARY['kbinput']()) + b.add_prim() + + b = Primitive('keyboard') + b.set_palette('sensor') + b.set_style('box-style') + b.set_label(_('keyboard')) + b.set_prim_name('keyboard') + b.set_value_block(True) + b.set_help(_('holds results of query-keyboard block')) + self.tw.lc._def_prim('keyboard', 0, lambda self: self.tw.lc.keyboard) + b.add_prim() + + b = Primitive('readpixel') + b.set_palette('sensor') + b.set_style('basic-style-extended-vertical') + b.set_label(_('read pixel')) + b.set_prim_name('readpixel') + b.set_help(_('RGB color under the turtle is pushed to the stack')) + PLUGIN_DICTIONARY['readpixel'] = self._prim_readpixel + self.tw.lc._def_prim('readpixel', 0, + lambda self: PLUGIN_DICTIONARY['readpixel']()) + b.add_prim() + + b = Primitive('see') + b.set_palette('sensor') + b.set_style('box-style') + b.set_label(_('turtle sees')) + b.set_prim_name('see') + b.set_help(_('returns the color that the turtle "sees"')) + b.set_value_block(True) + PLUGIN_DICTIONARY['see'] = self._prim_see + self.tw.lc._def_prim('see', 0, + lambda self: PLUGIN_DICTIONARY['see']()) + b.add_prim() + + b = Primitive('time') + b.set_palette('sensor') + b.set_style('box-style') + b.set_label(_('time')) + b.set_prim_name('time') + b.set_value_block(True) + b.set_help(_('elapsed time (in seconds) since program started')) + PLUGIN_DICTIONARY['time'] = self._prim_time + self.tw.lc._def_prim('time', 0, + lambda self: PLUGIN_DICTIONARY['time']()) + b.add_prim() + + def _extras_palette(self): + b = Primitive('push') + b.set_palette('extras') + b.set_style('basic-style-1arg') + b.set_label(_('push')) + b.set_prim_name('push') + b.set_help(_('pushes value onto FILO (first-in last-out heap)')) + PLUGIN_DICTIONARY['push'] = self._prim_push + self.tw.lc._def_prim('push', 1, + lambda self, x: PLUGIN_DICTIONARY['push'](x)) + b.add_prim() + + b = Primitive('printheap') + b.set_palette('extras') + b.set_style('basic-style-extended-vertical') + b.set_label(_('show heap')) + b.set_prim_name('printheap') + b.set_help(_('shows values in FILO (first-in last-out heap)')) + PLUGIN_DICTIONARY['printheap'] = self._prim_printheap + self.tw.lc._def_prim('printheap', 0, + lambda self: PLUGIN_DICTIONARY['printheap']()) + b.add_prim() + + b = Primitive('clearheap') + b.set_palette('extras') + b.set_style('basic-style-extended-vertical') + b.set_label(_('empty heap')) + b.set_prim_name('clearheap') + b.set_help(_('emptys FILO (first-in-last-out heap)')) + PLUGIN_DICTIONARY['clearheap'] = self._prim_emptyheap + self.tw.lc._def_prim('clearheap', 0, + lambda self: PLUGIN_DICTIONARY['clearheap']()) + b.add_prim() + + b = Primitive('pop') + b.set_palette('extras') + b.set_style('box-style') + b.set_label(_('pop')) + b.set_prim_name('pop') + b.set_value_block(True) + b.set_help(_('pops value off FILO (first-in last-out heap)')) + PLUGIN_DICTIONARY['pop'] = self._prim_pop + self.tw.lc._def_prim('pop', 0, + lambda self: PLUGIN_DICTIONARY['pop']()) + b.add_prim() + + b = Primitive('comment') + b.set_palette('extras') + b.set_style('basic-style-1arg') + b.set_label(_('comment')) + b.set_prim_name('comment') + b.set_default(_('comment')) + b.set_help(_('places a comment in your code')) + PLUGIN_DICTIONARY['print'] = self._prim_print + self.tw.lc._def_prim('comment', 1, + lambda self, x: PLUGIN_DICTIONARY['print'](x, True)) + b.add_prim() + + b = Primitive('print') + b.set_palette('extras') + b.set_style('basic-style-1arg') + b.set_label(_('print')) + b.set_prim_name('print') + b.set_help(_('prints value in status block at bottom of the screen')) + self.tw.lc._def_prim('print', 1, + lambda self, x: PLUGIN_DICTIONARY['print'](x, False)) + b.add_prim() + + b = Primitive('myfunc1arg') + b.set_palette('extras') + b.set_style('number-style-var-arg') + b.set_label([_('Python'), 'f(x)', 'x']) + b.set_prim_name('myfunction') + b.set_default(['x', 100]) + b.set_help(_('a programmable block: used to add advanced single-variable math equations, e.g., sin(x)')) + PLUGIN_DICTIONARY['myfunction'] = self._prim_myfunction + self.tw.lc._def_prim('myfunction', 2, + lambda self, f, x: PLUGIN_DICTIONARY['myfunction'](f, [x])) + b.add_prim() + + b = Primitive('myfunc2arg') + b.set_style('number-style-var-arg') + b.set_label([_('Python'), 'f(x,y)', 'x']) + b.set_prim_name('myfunction2') + b.set_default(['x+y', 100, 100]) + b.set_help(_('a programmable block: used to add advanced multi-variable math equations, e.g., sqrt(x*x+y*y)')) + self.tw.lc._def_prim('myfunction2', 3, + lambda self, f, x: PLUGIN_DICTIONARY['myfunction'](f, [x, y])) + b.add_prim() + + b = Primitive('myfunc3arg') + b.set_style('number-style-var-arg') + b.set_label([_('Python'), 'f(x,y,z)', 'x']) + b.set_prim_name('myfunction3') + b.set_default(['x+y+z', 100, 100, 100]) + b.set_help(_('a programmable block: used to add advanced multi-variable math equations, e.g., sin(x+y+z)')) + self.tw.lc._def_prim('myfunction3', 4, + lambda self, f, x, y, z: PLUGIN_DICTIONARY['myfunction']( + f, [x, y, z])) + b.add_prim() + + b = Primitive('userdefined') + b.set_palette('extras') + b.set_style('basic-style-var-arg') + b.set_label(' ') + b.set_prim_name('userdefined') + b.set_special_name(_('Python block')) + b.set_default(100) + b.set_help(_('runs code found in the tamyblock.py module found in the Journal')) + PLUGIN_DICTIONARY['userdefined'] = self._prim_myblock + self.tw.lc._def_prim('userdefined', 1, + lambda self, x: PLUGIN_DICTIONARY['userdefined']([x])) + b.add_prim() + + b = Primitive('userdefined2') + b.set_style('basic-style-var-arg') + b.set_label(' ') + b.set_prim_name('userdefined') + b.set_special_name(_('Python block')) + b.set_default([100, 100]) + b.set_help(_('runs code found in the tamyblock.py module found in the Journal')) + self.tw.lc._def_prim('userdefined2', 2, + lambda self, x, y: PLUGIN_DICTIONARY['userdefined']([x, y])) + b.add_prim() + + b = Primitive('userdefined3') + b.set_style('basic-style-var-arg') + b.set_label(' ') + b.set_prim_name('userdefined') + b.set_special_name(_('Python block')) + b.set_default([100, 100, 100]) + b.set_help(_('runs code found in the tamyblock.py module found in the Journal')) + self.tw.lc._def_prim('userdefined3', 3, + lambda self, x, y, z: PLUGIN_DICTIONARY['userdefined']([x, y, z])) + b.add_prim() + + b = Primitive('cartesian') + b.set_palette('extras') + b.set_style('basic-style-extended-vertical') + b.set_label(_('Cartesian')) + b.set_prim_name('cartesian') + b.set_help(_('displays Cartesian coordinates')) + self.tw.lc._def_prim('cartesian', 0, + lambda self: self.tw.set_cartesian(True)) + b.add_prim() + + b = Primitive('polar') + b.set_palette('extras') + b.set_style('basic-style-extended-vertical') + b.set_label(_('polar')) + b.set_prim_name('polar') + b.set_help(_('displays polar coordinates')) + self.tw.lc._def_prim('polar', 0, + lambda self: self.tw.set_polar(True)) + b.add_prim() + + b = Primitive('addturtle') + b.set_palette('extras') + b.set_style('basic-style-1arg') + b.set_label(_('turtle')) + b.set_prim_name('turtle') + b.set_default(1) + b.set_help(_('chooses which turtle to command')) + self.tw.lc._def_prim('turtle', 1, + lambda self, x: self.tw.canvas.set_turtle(x)) + b.add_prim() + + b = Primitive('skin') + b.set_style('basic-style-1arg') + b.set_label(_('turtle shell')) + b.set_prim_name('skin') + b.set_help(_("put a custom 'shell' on the turtle")) + PLUGIN_DICTIONARY['skin'] = self._prim_reskin + self.tw.lc._def_prim('skin', 1, + lambda self, x: PLUGIN_DICTIONARY['skin'](x)) + b.add_prim() + + b = Primitive('reskin') # macro + b.set_palette('extras') + b.set_style('basic-style-1arg') + b.set_label(_('turtle shell')) + b.set_help(_("put a custom 'shell' on the turtle")) + b.add_prim() + + b = Primitive('sandwichtop_no_label') + b.set_palette('extras') + b.set_style('collapsible-top-no-label') + b.set_label([' ', ' ']) + b.set_prim_name('nop') + b.set_help(_('top of a collapsed stack')) + b.add_prim() + + b = Primitive('sandwichbottom') + b.set_palette('extras') + b.set_style('collapsible-bottom') + b.set_label([' ', ' ']) + b.set_prim_name('nop') + b.set_help(_('bottom of a collapsed stack')) + b.add_prim() + + b = Primitive('sandwichcollapsed') + b.set_style('invisible') + b.set_label(' ') + b.set_prim_name('nop') + b.set_help(_('bottom block in a collapsed stack: click to open')) + b.add_prim() + + b = Primitive('sandwichtop') # depreciated + b.set_style('collapsible-top') + b.set_label(_('top of stack')) + b.set_default(_('label')) + b.set_prim_name('comment') + b.set_help(_('top of stack')) + b.add_prim() + + b = Primitive('sandwichtop_no_arm') # depreciated + b.set_style('collapsible-top-no-arm') + b.set_label(_('top of a collapsible stack')) + b.set_default(_('label')) + b.set_prim_name('comment') + b.set_help(_('top of stack')) + b.add_prim() + + b = Primitive('sandwichtop_no_arm_no_label') # depreciated + b.set_style('collapsible-top-no-arm-no-label') + b.set_label([' ', _('click to open')]) + b.set_prim_name('nop') + b.set_help(_('top of stack')) + b.add_prim() + + def _portfolio_palette(self): + b = Primitive('hideblocks') + b.set_palette('portfolio') + b.set_style('basic-style-extended-vertical') + b.set_label(_('hide blocks')) + b.set_prim_name('hideblocks') + b.set_help(_('declutters canvas by hiding blocks')) + self.tw.lc._def_prim('hideblocks', 0, lambda self: self.tw.hideblocks()) + b.add_prim() + + b = Primitive('showblocks') + b.set_palette('portfolio') + b.set_style('basic-style-extended-vertical') + b.set_label(_('show blocks')) + b.set_prim_name('showblocks') + b.set_help(_('restores hidden blocks')) + self.tw.lc._def_prim('showblocks', 0, lambda self: self.tw.showblocks()) + b.add_prim() + + b = Primitive('fullscreen') + b.set_palette('portfolio') + b.set_style('basic-style-extended-vertical') + b.set_label(_('full screen')) + b.set_prim_name('fullscreen') + b.set_help(_('hides the Sugar toolbars')) + self.tw.lc._def_prim('fullscreen', 0, + lambda self: self.tw.set_fullscreen()) + b.add_prim() + + b = Primitive('picturelist') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: list of bullets')) + b.add_prim() + + b = Primitive('picture1x1a') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: select Journal object (no description)')) + b.add_prim() + + b = Primitive('picture1x1') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: select Journal object (with description)')) + b.add_prim() + + b = Primitive('picture2x2') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: select four Journal objects')) + b.add_prim() + + b = Primitive('picture2x1') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: select two Journal objects')) + b.add_prim() + + b = Primitive('picture1x2') # macro + b.set_palette('portfolio') + b.set_style('basic-style-extended') + b.set_label(' ') + b.set_help(_('presentation template: select two Journal objects')) + b.add_prim() + + b = Primitive('leftpos') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('left')) + b.set_prim_name('lpos') + b.set_help(_('xcor of left of screen')) + self.tw.lc._def_prim('lpos', 0, lambda self: CONSTANTS['leftpos']) + b.add_prim() + + b = Primitive('bottompos') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('bottom')) + b.set_prim_name('bpos') + b.set_help(_('ycor of bottom of screen')) + self.tw.lc._def_prim('bpos', 0, lambda self: CONSTANTS['bottompos']) + b.add_prim() + + b = Primitive('width') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('width')) + b.set_prim_name('hres') + b.set_help(_('the canvas width')) + self.tw.lc._def_prim('hres', 0, lambda self: CONSTANTS['width']) + b.add_prim() + + b = Primitive('rightpos') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('right')) + b.set_prim_name('rpos') + b.set_help(_('xcor of right of screen')) + self.tw.lc._def_prim('rpos', 0, lambda self: CONSTANTS['rightpos']) + b.add_prim() + + b = Primitive('toppos') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('top')) + b.set_prim_name('tpos') + b.set_help(_('ycor of top of screen')) + self.tw.lc._def_prim('tpos', 0, lambda self: CONSTANTS['toppos']) + b.add_prim() + + b = Primitive('height') + b.set_palette('portfolio') + b.set_style('box-style') + b.set_label(_('height')) + b.set_prim_name('vres') + b.set_help(_('the canvas height')) + self.tw.lc._def_prim('vres', 0, lambda self: CONSTANTS['height']) + b.add_prim() + + b = Primitive('titlex') + b.set_style('box-style') + b.set_label(_('title x')) + b.set_prim_name('titlex') + self.tw.lc._def_prim('titlex', 0, lambda self: CONSTANTS['titlex']) + b.add_prim() + + b = Primitive('titley') + b.set_style('box-style') + b.set_label(_('title y')) + b.set_prim_name('titley') + self.tw.lc._def_prim('titley', 0, lambda self: CONSTANTS['titley']) + b.add_prim() + + b = Primitive('leftx') + b.set_style('box-style') + b.set_label(_('left x')) + b.set_prim_name('leftx') + self.tw.lc._def_prim('leftx', 0, lambda self: CONSTANTS['leftx']) + b.add_prim() + + b = Primitive('topy') + b.set_style('box-style') + b.set_label(_('top y')) + b.set_prim_name('topy') + self.tw.lc._def_prim('topy', 0, lambda self: CONSTANTS['topy']) + b.add_prim() + + b = Primitive('rightx') + b.set_style('box-style') + b.set_label(_('right x')) + b.set_prim_name('rightx') + self.tw.lc._def_prim('rightx', 0, lambda self: CONSTANTS['rightx']) + b.add_prim() + + b = Primitive('bottomy') + b.set_style('box-style') + b.set_label(_('bottom y')) + b.set_prim_name('bottomy') + self.tw.lc._def_prim('bottomy', 0, lambda self: CONSTANTS['bottomy']) + b.add_prim() + + # Block primitives + + def _prim_emptyheap(self): + """ Empty FILO """ + self.tw.lc.heap = [] + + def _prim_kbinput(self): + """ Query keyboard """ + if len(self.tw.keypress) == 1: + self.tw.lc.keyboard = ord(self.tw.keypress[0]) + else: + try: + self.tw.lc.keyboard = {'Escape': 27, 'space': 32, ' ': 32, + 'Return': 13, 'KP_Up': 2, 'KP_Down': 4, 'KP_Left': 1, + 'KP_Right': 3}[self.tw.keypress] + except KeyError: + self.tw.lc.keyboard = 0 + self.tw.lc.update_label_value('keyboard', self.tw.lc.keyboard) + self.tw.keypress = '' + + def _prim_myblock(self, x): + """ Run Python code imported from Journal """ + if self.tw.lc.bindex is not None and \ + self.tw.lc.bindex in self.tw.myblock: + try: + if len(x) == 1: + myfunc_import(self, self.tw.myblock[self.tw.lc.bindex], + x[0]) + else: + myfunc_import(self, self.tw.myblock[self.tw.lc.bindex], x) + except: + raise logoerror("#syntaxerror") + + def _prim_myfunction(self, f, x): + """ Programmable block """ + try: + y = myfunc(f, x) + if str(y) == 'nan': + debug_output('Python function returned NAN', + self.tw.running_sugar) + self.tw.lc.stop_logo() + raise logoerror("#notanumber") + else: + return y + except ZeroDivisionError: + self.tw.lc.stop_logo() + raise logoerror("#zerodivide") + except ValueError, e: + self.tw.lc.stop_logo() + raise logoerror('#' + str(e)) + except SyntaxError, e: + self.tw.lc.stop_logo() + raise logoerror('#' + str(e)) + except NameError, e: + self.tw.lc.stop_logo() + raise logoerror('#' + str(e)) + except OverflowError: + self.tw.lc.stop_logo() + raise logoerror("#overflowerror") + except TypeError: + self.tw.lc.stop_logo() + raise logoerror("#notanumber") + + def _prim_pop(self): + """ Pop value off of FILO """ + if len(self.tw.lc.heap) == 0: + raise logoerror("#emptyheap") + else: + if len(self.tw.lc.heap) == 1: + self.tw.lc.update_label_value('pop') + else: + self.tw.lc.update_label_value('pop', self.tw.lc.heap[-2]) + return self.tw.lc.heap.pop(-1) + + def _prim_print(self, n, flag): + """ Print object n """ + if flag and (self.tw.hide or self.tw.step_time == 0): + return + if type(n) == str or type(n) == unicode: + if n[0:6] == 'media_' and \ + n[6:].lower not in MEDIA_BLOCKS_DICTIONARY: + try: + if self.tw.running_sugar: + try: + dsobject = datastore.get(n[6:]) + except: + debug_output("Couldn't open %s" % (n[6:]), + self.tw.running_sugar) + self.tw.showlabel('status', dsobject.metadata['title']) + dsobject.destroy() + else: + self.tw.showlabel('status', n[6:]) + except IOError: + self.tw.showlabel('status', n) + else: + self.tw.showlabel('status', n) + elif type(n) == int: + self.tw.showlabel('status', n) + else: + self.tw.showlabel('status', + str(round_int(n)).replace('.', self.tw.decimal_point)) + + def _prim_printheap(self): + """ Display contents of heap """ + self.tw.showlabel('status', str(self.tw.lc.heap) + ' ') + + def _prim_push(self, val): + """ Push value onto FILO """ + self.tw.lc.heap.append(val) + self.tw.lc.update_label_value('pop', val) + + def _prim_readpixel(self): + """ Read r, g, b, a from the canvas and push b, g, r to the stack """ + r, g, b, a = self.tw.canvas.get_pixel() + self.tw.lc.heap.append(b) + self.tw.lc.heap.append(g) + self.tw.lc.heap.append(r) + + def _prim_reskin(self, media): + """ Reskin the turtle with an image from a file """ + scale = int(ICON_SIZE * float(self.tw.lc.scale) / DEFAULT_SCALE) + if scale < 1: + return + self.tw.lc.filepath = None + dsobject = None + if os.path.exists(media[6:]): # is it a path? + self.tw.lc.filepath = media[6:] + elif self.tw.running_sugar: # is it a datastore object? + try: + dsobject = datastore.get(media[6:]) + except: + debug_output("Couldn't open skin %s" % (media[6:]), + self.tw.running_sugar) + if dsobject is not None: + self.tw.lc.filepath = dsobject.file_path + if self.tw.lc.filepath == None: + self.tw.showlabel('nojournal', self.tw.lc.filepath) + return + pixbuf = None + try: + print self.tw.lc.filepath, scale, scale + pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(self.tw.lc.filepath, + scale, scale) + except: + self.tw.showlabel('nojournal', self.tw.lc.filepath) + debug_output("Couldn't open skin %s" % (self.tw.lc.filepath), + self.tw.running_sugar) + if pixbuf is not None: + self.tw.active_turtle.set_shapes([pixbuf]) + pen_state = self.tw.active_turtle.get_pen_state() + if pen_state: + self.tw.canvas.setpen(False) + self.tw.canvas.forward(0) + if pen_state: + self.tw.canvas.setpen(True) + + def _prim_save_picture(self, name): + """ Save canvas to file as PNG """ + self.tw.save_as_image(name) + + def _prim_save_svg(self, name): + """ Save SVG to file """ + self.tw.canvas.svg_close() + self.tw.save_as_image(name, True) + + def _prim_see(self): + """ Read r, g, b from the canvas and return a corresponding palette + color """ + r, g, b, a = self.tw.canvas.get_pixel() + color_index = self.tw.canvas.get_color_index(r, g, b) + self.tw.lc.update_label_value('see', color_index) + return color_index + + def _prim_setscale(self, scale): + """ Set the scale used by the show block """ + self.tw.lc.scale = scale + self.tw.lc.update_label_value('scale', scale) + + def _prim_show(self, string, center=False): + """ Show is the general-purpose media-rendering block. """ + if type(string) == str or type(string) == unicode: + if string in ['media_', 'descr_', 'audio_', 'video_', + 'media_None', 'descr_None', 'audio_None', + 'video_None']: + pass + elif string[0:6] in ['media_', 'descr_', 'audio_', 'video_']: + self.tw.lc.filepath = None + self.tw.lc.dsobject = None + print string[6:], MEDIA_BLOCKS_DICTIONARY + if string[6:].lower() in MEDIA_BLOCKS_DICTIONARY: + MEDIA_BLOCKS_DICTIONARY[string[6:].lower()]() + elif os.path.exists(string[6:]): # is it a path? + self.tw.lc.filepath = string[6:] + elif self.tw.running_sugar: # is it a datastore object? + try: + self.tw.lc.dsobject = datastore.get(string[6:]) + except: + debug_output("Couldn't find dsobject %s" % ( + string[6:]), self.tw.running_sugar) + if self.tw.lc.dsobject is not None: + self.tw.lc.filepath = self.tw.lc.dsobject.file_path + if self.tw.lc.filepath == None: + if self.tw.lc.dsobject is not None: + self.tw.showlabel('nojournal', + self.tw.lc.dsobject.metadata['title']) + else: + self.tw.showlabel('nojournal', string[6:]) + debug_output("Couldn't open %s" % (string[6:]), + self.tw.running_sugar) + elif string[0:6] == 'media_': + self.tw.lc._insert_image(center) + elif string[0:6] == 'descr_': + mimetype = None + if self.tw.lc.dsobject is not None and \ + 'mime_type' in self.tw.lc.dsobject.metadata: + mimetype = self.tw.lc.dsobject.metadata['mime_type'] + description = None + if self.tw.lc.dsobject is not None and \ + 'description' in self.tw.lc.dsobject.metadata: + description = self.tw.lc.dsobject.metadata['description'] + self.tw.lc._insert_desc(mimetype, description) + elif string[0:6] == 'audio_': + self.tw.lc._play_sound() + elif string[0:6] == 'video_': + self.tw.lc._play_video() + if self.tw.lc.dsobject is not None: + self.tw.lc.dsobject.destroy() + else: # assume it is text to display + x, y = self.tw.lc._x(), self.tw.lc._y() + if center: + y -= self.tw.canvas.textsize + self.tw.canvas.draw_text(string, x, y, + int(self.tw.canvas.textsize * \ + self.tw.lc.scale / 100.), + self.tw.canvas.width - x) + elif type(string) == float or type(string) == int: + string = round_int(string) + x, y = self.tw.lc._x(), self.tw.lc._y() + if center: + y -= self.tw.canvas.textsize + self.tw.canvas.draw_text(string, x, y, + int(self.tw.canvas.textsize * \ + self.tw.lc.scale / 100.), + self.tw.canvas.width - x) + + def _prim_time(self): + """ Number of seconds since program execution has started or + clean (prim_clear) block encountered """ + elapsed_time = int(time() - self.tw.lc._start_time) + self.tw.lc.update_label_value('time', elapsed_time) + return elapsed_time + + # Depreciated blocks + + """ +PORTFOLIO_STYLE_2x2 = ['template2x2'] +PORTFOLIO_STYLE_1x1 = ['template1x1', 'template1x1a'] +PORTFOLIO_STYLE_2x1 = ['template2x1'] +PORTFOLIO_STYLE_1x2 = ['template1x2'] + 'template1x1': [' '], + 'template1x1a': [' '], + 'template1x2': [' '], + 'template2x1': [' '], + 'template2x2': [' '], + 'templatelist': [' '], + 'template1x1': 't1x1', + 'template1x1a': 't1x1a', + 'template1x2': 't1x2', + 'template2x1': 't2x1', + 'template2x2': 't2x2', + 'templatelist': 'bullet', + + 't1x1': [2, lambda self, x, y: self._show_template1x1(x, y)], + 't1x1a': [2, lambda self, x, y: self._show_template1x1a(x, y)], + 't1x2': [3, lambda self, x, y, z: self._show_template1x2(x, y, z)], + 't2x1': [3, lambda self, x, y, z: self._show_template2x1(x, y, z)], + 't2x2': [5, lambda self, x, y, z, a, b: self._show_template2x2( + x, y, z, a, b)], + 'write': [2, lambda self, x, y: self._write(self, x, y)] + 'template1x1': [_('Title'), 'None'], + 'template1x1a': [_('Title'), 'None'], + 'template1x2': [_('Title'), 'None', 'None'], + 'template2x1': [_('Title'), 'None', 'None'], + 'template2x2': [_('Title'), 'None', 'None', 'None', 'None'], + 'templatelist': [_('Title'), '∙ '], + 'write': [_('text'), 32]} + + 'template1x1a': _('presentation 1x1'), + 'template1x2': _('presentation 1x2'), + 'template2x1': _('presentation 2x1'), + 'template2x2': _('presentation 2x2'), + 'templatelist': _('presentation bulleted list'), + 'template1x1': _( + "presentation template: select Journal object (with description)"), + 'template1x1a': _( + "presentation template: select Journal object (no description)"), + 'template1x2': _("presentation template: select two Journal objects"), + 'template2x1': _("presentation template: select two Journal objects"), + 'template2x2': _("presentation template: select four Journal objects"), + 'templatelist': _("presentation template: list of bullets"), + """ + + def _show_template1x1(self, title, media): + """ title, one image, and description """ + xo = self.tw.calc_position('t1x1')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(title) + # calculate and set scale for media blocks + myscale = 45 * (self.tw.canvas.height - self.title_height * 2) \ + / self.tw.canvas.height + self._prim_setscale(myscale) + # set body text size + self.tw.canvas.settextsize(self.body_height) + # render media object + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media) + if self.tw.running_sugar: + x = 0 + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media.replace('media_', 'descr_')) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _show_template2x1(self, title, media1, media2): + """ title, two images (horizontal), two descriptions """ + xo = self.tw.calc_position('t2x1')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(title) + # calculate and set scale for media blocks + myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ + self.tw.canvas.height + self._prim_setscale(myscale) + # set body text size + self.tw.canvas.settextsize(self.body_height) + # render four quadrents + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1) + x = 0 + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media2) + y = -self.title_height + if self.tw.running_sugar: + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media2.replace('media_', 'descr_')) + x = -(self.tw.canvas.width / 2) + xo + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1.replace('media_', 'descr_')) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _show_bullets(self, sarray): + """ title and varible number of bullets """ + xo = self.tw.calc_position('bullet')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(sarray[0]) + # set body text size + self.tw.canvas.settextsize(self.bullet_height) + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + for s in sarray[1:]: + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(s) + y -= int(self.bullet_height * 2 * self.tw.lead) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _show_template1x2(self, title, media1, media2): + """ title, two images (vertical), two desciptions """ + xo = self.tw.calc_position('t1x2')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(title) + # calculate and set scale for media blocks + myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ + self.tw.canvas.height + self._prim_setscale(myscale) + # set body text size + self.tw.canvas.settextsize(self.body_height) + # render four quadrents + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1) + if self.tw.running_sugar: + x = 0 + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1.replace('media_', 'descr_')) + y = -self.title_height + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media2.replace('media_', 'descr_')) + x = -(self.tw.canvas.width / 2) + xo + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media2) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _show_template2x2(self, title, media1, media2, media3, media4): + """ title and four images """ + xo = self.tw.calc_position('t2x2')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(title) + # calculate and set scale for media blocks + myscale = 45 * (self.tw.canvas.height - self.title_height * 2) / \ + self.tw.canvas.height + self._prim_setscale(myscale) + # set body text size + self.tw.canvas.settextsize(self.body_height) + # render four quadrents + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1) + x = 0 + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media2) + y = -self.title_height + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media4) + x = -(self.tw.canvas.width / 2) + xo + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media3) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _show_template1x1a(self, title, media1): + """ title, one media object """ + xo = self.tw.calc_position('t1x1a')[2] + x = -(self.tw.canvas.width / 2) + xo + y = self.tw.canvas.height / 2 + self.tw.canvas.setxy(x, y, pendown=False) + # save the text size so we can restore it later + save_text_size = self.tw.canvas.textsize + # set title text + self.tw.canvas.settextsize(self.title_height) + self._prim_show(title) + # calculate and set scale for media blocks + myscale = 90 * (self.tw.canvas.height - self.title_height * 2) / \ + self.tw.canvas.height + self._prim_setscale(myscale) + # set body text size + self.tw.canvas.settextsize(self.body_height) + # render media object + # leave some space below the title + y -= int(self.title_height * 2 * self.tw.lead) + self.tw.canvas.setxy(x, y, pendown=False) + self._prim_show(media1) + # restore text size + self.tw.canvas.settextsize(save_text_size) + + def _write(self, string, fsize): + """ Write string at size """ + x = self.tw.canvas.width / 2 + int(self.tw.canvas.xcor) + y = self.tw.canvas.height / 2 - int(self.tw.canvas.ycor) + self.tw.canvas.draw_text(string, x, y - 15, int(fsize), + self.tw.canvas.width) -- cgit v0.9.1