diff options
author | Walter Bender <walter@sugarlabs.org> | 2010-08-12 17:57:55 (GMT) |
---|---|---|
committer | Walter Bender <walter@sugarlabs.org> | 2010-08-12 17:57:55 (GMT) |
commit | c2937d9fdd30b1b896caf66851d6677924d07488 (patch) | |
tree | c242386fa59755d4adea7fb414b72466181a2a2e /TurtleArt/talogo.py | |
parent | 98caa09b7eadbd14776b73f01095bc59cb39cc18 (diff) |
reorg of module heirarchy
Diffstat (limited to 'TurtleArt/talogo.py')
-rw-r--r-- | TurtleArt/talogo.py | 1366 |
1 files changed, 1366 insertions, 0 deletions
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py new file mode 100644 index 0000000..318bb7e --- /dev/null +++ b/TurtleArt/talogo.py @@ -0,0 +1,1366 @@ +# -*- coding: utf-8 -*- +#Copyright (c) 2007-8, Playful Invention Company. +#Copyright (c) 2008-10, Walter Bender +#Copyright (c) 2008-10, Raúl Gutiérrez Segalés + +#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 clock +from math import sqrt +from random import uniform +from operator import isNumberType +from UserDict import UserDict +try: + from sugar.datastore import datastore +except: + pass + +from taconstants import PALETTES, PALETTE_NAMES, TAB_LAYER, BLACK, WHITE +from tagplay import play_audio, play_movie_from_file, stop_media +from tajail import myfunc, myfunc_import +from tautils import get_pixbuf_from_journal, movie_media_type, convert, \ + audio_media_type, text_media_type, round_int, chr_to_ord, \ + strtype +from gettext import gettext as _ + +class noKeyError(UserDict): + __missing__ = lambda x, y: 0 + +class symbol: + def __init__(self, name): + self.name = name + self.nargs = None + self.fcn = None + + def __str__(self): + return self.name + def __repr__(self): + return '#' + self.name + +class logoerror(Exception): + def __init__(self, value): + self.value = value + def __str__(self): + return repr(self.value) + +# Utility functions + +def numtype(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 str_to_num(x): + """ Try to comvert a string to a number """ + xx = convert(x, float) + if type(xx) is float: + return xx + else: + xx, xflag = chr_to_ord(x) + if xflag: + return xx + else: + raise logoerror("#syntaxerror") + +def taand(x, y): + """ Logical and """ + return x&y + +def taor(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 str_to_num(x) / str_to_num(y) + except ZeroDivisionError: + raise logoerror("#zerodivide") + except ValueError: + raise logoerror("#syntaxerror") + +def taequal(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 str_to_num(x) == str_to_num(y) + except ValueError: + raise logoerror("#syntaxerror") + +def taless(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 str_to_num(x) < str_to_num(y) + except TypeError: + raise logoerror("#syntaxerror") + +def tamore(x, y): + """ Compare numbers and strings """ + return taless(y, x) + +def taplus(x, y): + """ Add numbers, concat strings """ + if numtype(x) and numtype(y): + return(x+y) + else: + if numtype(x): + xx = str(round_int(x)) + else: + xx = str(x) + if numtype(y): + yy = str(round_int(y)) + else: + yy = str(y) + return(xx+yy) + +def taminus(x, y): + """ Numerical subtraction """ + if numtype(x) and numtype(y): + return(x-y) + try: + return str_to_num(x) - str_to_num(y) + except TypeError: + raise logoerror("#syntaxerror") + +def taproduct(x, y): + """ Numerical multiplication """ + if numtype(x) and numtype(y): + return(x*y) + try: + return str_to_num(x) * str_to_num(y) + except TypeError: + raise logoerror("#syntaxerror") + +def tamod(x, y): + """ Numerical mod """ + if numtype(x) and numtype(y): + return(x%y) + try: + return str_to_num(x) % str_to_num(y) + except TypeError: + raise logoerror("#syntaxerror") + except ValueError: + raise logoerror("#syntaxerror") + +def tasqrt(x): + """ Square root """ + if numtype(x): + if x < 0: + raise logoerror("#negroot") + return sqrt(x) + try: + return sqrt(str_to_num(x)) + except ValueError: + raise logoerror("#negroot") + except TypeError: + raise logoerror("#syntaxerror") + +def tarandom(x, y): + """ Random integer """ + if numtype(x) and numtype(y): + return(int(uniform(x, y))) + xx, xflag = chr_to_ord(x) + yy, yflag = chr_to_ord(y) + print xx, xflag, yy, yflag + if xflag and yflag: + return chr(int(uniform(xx, yy))) + if not xflag: + xx = str_to_num(x) + if not yflag: + yy = str_to_num(y) + try: + return(int(uniform(xx, yy))) + except TypeError: + raise logoerror("#syntaxerror") + +def identity(x): + """ Identity function """ + return(x) + +def stop_logo(tw): + """ Stop logo is called from the Stop button on the toolbar """ + tw.step_time = 0 + tw.lc.step = just_stop() + tw.turtles.show_all() + +def just_stop(): + """ yield False to stop stack """ + yield False + +def millis(): + """ Current time in milliseconds """ + return int(clock()*1000) + +""" +A class for parsing Logo Code +""" +class LogoCode: + def __init__(self, tw): + + self.tw = tw + self.oblist = {} + + DEFPRIM = { + '(':[1, lambda self, x: self.prim_opar(x)], + 'and':[2, lambda self, x, y: taand(x, y)], + 'arc':[2, lambda self, x, y: self.tw.canvas.arc(x, y)], + 'back':[1, lambda self, x: self.tw.canvas.forward(-x)], + 'black':[0, lambda self: BLACK], + 'blue':[0, lambda self: 70], + 'bpos':[0, lambda self: -self.tw.canvas.height/(self.tw.coord_scale*2)], + 'boty':[0, lambda self: self.tw.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: 50], + 'define':[2, self.prim_define], + 'division':[2, lambda self, x, y: careful_divide(x, y)], + 'equal?':[2, lambda self,x, y: taequal(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.tw.canvas.forward(x)], + 'fullscreen':[0, lambda self: self.tw.set_fullscreen()], + 'greater?':[2, lambda self, x, y: tamore(x, y)], + 'green':[0, lambda self: 30], + 'heading':[0, lambda self: self.tw.canvas.heading], + 'hideblocks':[0, lambda self: self.tw.hideblocks()], + 'hres':[0, lambda self: self.tw.canvas.width/self.tw.coord_scale], + '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(x, False)], + 'kbinput':[0, lambda self: self.prim_kbinput()], + 'keyboard':[0, lambda self: self.keyboard], + 'left':[1, lambda self, x: self.tw.canvas.right(-x)], + 'leftx':[0, lambda self: self.tw.leftx], + 'lpos':[0, lambda self: -self.tw.canvas.width/(self.tw.coord_scale*2)], + 'less?':[2, lambda self, x, y: taless(x, y)], + 'minus':[2, lambda self, x, y: taminus(x, y)], + 'mod':[2, lambda self, x, y: tamod(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: 10], + 'or':[2, lambda self, x, y: taor(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: taplus(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: taproduct(x, y)], + 'purple':[0, lambda self: 90], + 'push':[1, lambda self, x: self.prim_push(x)], + 'random':[2, lambda self, x, y: tarandom(x, y)], + 'red':[0, lambda self: 0], + 'repeat':[2, self.prim_repeat, True], + 'right':[1, lambda self, x: self.tw.canvas.right(x)], + 'rightx':[0, lambda self: self.tw.rightx], + 'rpos':[0, lambda self: self.tw.canvas.width/(self.tw.coord_scale*2)], + 'savepix':[1, lambda self, x: self.save_picture(x)], + 'savesvg':[1, lambda self, x: self.save_svg(x)], + 'scale':[0, lambda self: self.scale], + 'setcolor':[1, lambda self, x: self.tw.canvas.setcolor(x)], + 'setgray':[1, lambda self, x: self.tw.canvas.setgray(x)], + 'seth':[1, lambda self, x: self.tw.canvas.seth(x)], + 'setpensize':[1, lambda self, x: self.tw.canvas.setpensize(x)], + 'setscale':[1, lambda self, x: self.set_scale(x)], + 'setshade':[1, lambda self, x: 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)], + 'setxy':[2, lambda self, x, y: self.tw.canvas.setxy(x, y)], + '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()], + 'sound':[1, lambda self, x: self.play_sound(x)], + 'sqrt':[1, lambda self, x: tasqrt(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], + 'titlex':[0, lambda self: self.tw.titlex], + 'titley':[0, lambda self: self.tw.titley], + 'topy':[0, lambda self: self.tw.topy], + 'tpos':[0, lambda self: self.tw.canvas.height/(self.tw.coord_scale*2)], + '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_movie(x)], + 'vres':[0, lambda self: self.tw.canvas.height/self.tw.coord_scale], + 'wait':[1, self.prim_wait, True], + # 'while':[2, self.prim_while, 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: 20]} + + for p in iter(DEFPRIM): + if len(DEFPRIM[p]) == 2: + self.defprim(p, DEFPRIM[p][0], DEFPRIM[p][1]) + else: + self.defprim(p, DEFPRIM[p][0], DEFPRIM[p][1], DEFPRIM[p][2]) + + self.symtype = type(self.intern('print')) + self.listtype = type([]) + self.symnothing = self.intern('%nothing%') + self.symopar = self.intern('(') + self.iline = None + self.cfun = None + self.arglist = None + self.ufun = None + self.procstop = False + self.running = False + self.istack = [] + self.stacks = {} + self.boxes = {'box1': 0, 'box2': 0} + self.heap = [] + self.iresults = None + self.step = None + + self.keyboard = 0 + self.trace = 0 + self.gplay = None + self.ag = None + self.filepath = None + + # Scale factors for depreciated portfolio blocks + self.title_height = int((self.tw.canvas.height/20)*self.tw.scale) + self.body_height = int((self.tw.canvas.height/40)*self.tw.scale) + self.bullet_height = int((self.tw.canvas.height/30)*self.tw.scale) + + self.scale = 33 + + def defprim(self, name, args, fcn, rprim=False): + """ Define the primitives associated with the blocks """ + sym = self.intern(name) + sym.nargs, sym.fcn = args, fcn + sym.rprim = rprim + + def intern(self, string): + """ Add any new objects to the symbol list. """ + if string in self.oblist: + return self.oblist[string] + sym = symbol(string) + self.oblist[string] = sym + return sym + + def run_blocks(self, blk, blocks, run_flag): + """ Given a block to run... """ + for k in self.stacks.keys(): + self.stacks[k] = None + self.stacks['stack1'] = None + self.stacks['stack2'] = None + self.tw.saving_svg = False + + for b in blocks: + b.unhighlight() + if b.name == 'hat1': + code = self.blocks_to_code(b) + self.stacks['stack1'] = self.readline(code) + if b.name == 'hat2': + code = self.blocks_to_code(b) + self.stacks['stack2'] = self.readline(code) + if b.name == 'hat': + if b.connections[1] is not None: + code = self.blocks_to_code(b) + x = b.connections[1].values[0] + if type(convert(x, float, False)) == float: + if int(float(x)) == x: + x = int(x) + self.stacks['stack3'+str(x)] = self.readline(code) + + code = self.blocks_to_code(blk) + if run_flag: + print "running code: %s" % (code) + self.setup_cmd(code) + if self.tw.hide is False: + self.tw.display_coordinates() + else: + return code + + def blocks_to_code(self, blk): + """ Convert a stack of blocks to pseudocode. """ + if blk is None: + return ['%nothing%', '%nothing%'] + code = [] + dock = blk.docks[0] + if len(dock)>4: # There could be a '(', ')', '[' or ']'. + code.append(dock[4]) + if blk.name == 'savesvg': + self.tw.saving_svg = True + if blk.primitive is not None: # make a tuple (prim, blk) + code.append((blk.primitive, self.tw.block_list.list.index(blk))) + elif len(blk.values)>0: # Extract the value from content blocks. + if blk.name == 'number': + try: + code.append(float(blk.values[0])) + except ValueError: + code.append(float(ord(blk.values[0][0]))) + elif blk.name == 'string' or blk.name == 'title': + if type(blk.values[0]) == float or type(blk.values[0]) == int: + if int(blk.values[0]) == blk.values[0]: + blk.values[0] = int(blk.values[0]) + code.append('#s'+str(blk.values[0])) + else: + code.append('#s'+blk.values[0]) + elif blk.name == 'journal': + if blk.values[0] is not None: + code.append('#smedia_'+str(blk.values[0])) + else: + code.append('#smedia_None') + elif blk.name == 'description': + if blk.values[0] is not None: + code.append('#sdescr_'+str(blk.values[0])) + else: + code.append('#sdescr_None') + elif blk.name == 'audio': + if blk.values[0] is not None: + code.append('#saudio_'+str(blk.values[0])) + else: + code.append('#saudio_None') + else: + return ['%nothing%'] + else: + return ['%nothing%'] + if blk.connections is not None and len(blk.connections) > 0: + for i in range(1, len(blk.connections)): + b = blk.connections[i] + dock = blk.docks[i] + if len(dock)>4: # There could be a '(', ')', '[' or ']'. + for c in dock[4]: + code.append(c) + if b is not None: + code.extend(self.blocks_to_code(b)) + elif blk.docks[i][0] not in ['flow', 'unavailable']: + code.append('%nothing%') + return code + + def setup_cmd(self, string): + """ Execute the psuedocode. """ + self.tw.active_turtle.hide() # Hide the turtle while we are running. + self.procstop = False + blklist = self.readline(string) + self.step = self.start_eval(blklist) + + """ + Convert the pseudocode into a list of commands. + The block associated with the command is stored as the second element + in a tuple, e.g., (#forward, 16) + """ + def readline(self, line): + res = [] + while line: + token = line.pop(0) + bindex = None + if type(token) == tuple: + (token, bindex) = token + if isNumberType(token): + res.append(token) + elif token.isdigit(): + res.append(float(token)) + elif token[0] == '-' and token[1:].isdigit(): + res.append(-float(token[1:])) + elif token[0] == '"': + res.append(token[1:]) + elif token[0:2] == "#s": + res.append(token[2:]) + elif token == '[': + res.append(self.readline(line)) + elif token == ']': + return res + elif bindex is None or type(bindex) is not int: + res.append(self.intern(token)) + else: + res.append((self.intern(token), bindex)) + return res + + def start_eval(self, blklist): + """ Step through the list. """ + if self.tw.running_sugar: + self.tw.activity.stop_turtle_button.set_icon("stopiton") + elif self.tw.interactive_mode: + self.tw.toolbar_shapes['stopiton'].set_layer(TAB_LAYER) + self.running = True + self.icall(self.evline, blklist) + yield True + if self.tw.running_sugar: + self.tw.activity.stop_turtle_button.set_icon("stopitoff") + elif self.tw.interactive_mode: + self.tw.toolbar_shapes['stopiton'].hide() + yield False + self.running = False + + def icall(self, fcn, *args): + """ Add a function and its arguments to the program stack. """ + self.istack.append(self.step) + self.step = fcn(*(args)) + + def evline(self, blklist): + """ Evaluate a line of code from the list. """ + oldiline = self.iline + self.iline = blklist[:] + self.arglist = None + while self.iline: + token = self.iline[0] + bindex = None + if type(token) == tuple: + (token, bindex) = self.iline[0] + + # If the blocks are visible, highlight the current block. + if not self.tw.hide and bindex is not None: + self.tw.block_list.list[bindex].highlight() + + # In debugging modes, we pause between steps and show the turtle. + if self.tw.step_time > 0: + self.tw.active_turtle.show() + endtime = millis()+self.an_int(self.tw.step_time)*100 + while millis()<endtime: + yield True + self.tw.active_turtle.hide() + + # 'Stand-alone' booleans are handled here. + if token == self.symopar: + token = self.iline[1] + if type(token) == tuple: + (token, bindex) = self.iline[1] + + # Process the token and any arguments. + self.icall(self.eval) + yield True + + # Time to unhighlight the current block. + if not self.tw.hide and bindex is not None: + self.tw.block_list.list[bindex].unhighlight() + + if self.procstop: + break + if self.iresult == None: + continue + + if bindex is not None: + self.tw.block_list.list[bindex].highlight() + raise logoerror(str(self.iresult)) + self.iline = oldiline + self.ireturn() + if self.tw.hide is False and self.tw.step_time > 0: + self.tw.display_coordinates() + yield True + + def eval(self): + """ Evaluate the next token on the line of code we are processing. """ + token = self.iline.pop(0) + bindex = None + if type(token) == tuple: + (token, bindex) = token + + # Either we are processing a symbol or a value. + if type(token) == self.symtype: + # We highlight blocks here in case an error occurs... + # print "> ", token + if not self.tw.hide and bindex is not None: + self.tw.block_list.list[bindex].highlight() + self.icall(self.evalsym, token) + yield True + # and unhighlight if everything was OK. + if not self.tw.hide and bindex is not None: + self.tw.block_list.list[bindex].unhighlight() + res = self.iresult + else: + # print ": ", token + res = token + + self.ireturn(res) + yield True + + def evalsym(self, token): + """ Process primitive associated with symbol token """ + self.debug_trace(token) + self.undefined_check(token) + oldcfun, oldarglist = self.cfun, self.arglist + self.cfun, self.arglist = token, [] + + if token.nargs == None: + raise logoerror("#noinput") + for i in range(token.nargs): + self.no_args_check() + self.icall(self.eval) + yield True + self.arglist.append(self.iresult) + if self.cfun.rprim: + if type(self.cfun.fcn) == self.listtype: + print "evalsym rprim list: ", token + self.icall(self.ufuncall, self.cfun.fcn) + yield True + else: + # print "evalsym rprim: ", token + self.icall(self.cfun.fcn, *self.arglist) + yield True + result = None + else: + # print "evalsym: ", token + result = self.cfun.fcn(self, *self.arglist) + self.cfun, self.arglist = oldcfun, oldarglist + if self.arglist is not None and result == None: + raise logoerror("%s %s %s" % \ + (oldcfun.name, _("did not output to"), self.cfun.name)) + self.ireturn(result) + yield True + + def ufuncall(self, body): + """ ufuncall """ + self.ijmp(self.evline, body) + yield True + + def doevalstep(self): + """ evaluate one step """ + starttime = millis() + try: + while (millis()-starttime)<120: + try: + if self.step is not None: + self.step.next() + else: + return False + except StopIteration: + self.tw.turtles.show_all() + return False + except logoerror, e: + self.tw.showlabel('syntaxerror', str(e)[1:-1]) + self.tw.turtles.show_all() + return False + return True + + def ireturn(self, res=None): + """ return value """ + self.step = self.istack.pop() + self.iresult = res + + def ijmp(self, fcn, *args): + """ ijmp """ + self.step = fcn(*(args)) + + def debug_trace(self, token): + """ Display debugging information """ + if self.trace: + if token.name in PALETTES[PALETTE_NAMES.index('turtle')]: + my_string = "%s\n%s=%d\n%s=%d\n%s=%d\n%s=%d" % \ + (token.name, _('xcor'), int(self.tw.canvas.xcor), + _('ycor'), int(self.tw.canvas.ycor), _('heading'), + int(self.tw.canvas.heading), _('scale'), int(self.scale)) + elif token.name in PALETTES[PALETTE_NAMES.index('pen')]: + if self.tw.canvas.pendown: + penstatus = _('pen down') + else: + penstatus = _('pen up') + my_string = "%s\n%s\n%s=%d\n%s=%d\n%s=%.1f" % \ + (token.name, penstatus, _('color'), + int(self.tw.canvas.color), _('shade'), + int(self.tw.canvas.shade), _('pen size'), + self.tw.canvas.pensize) + else: + my_string = "%s\n" % (token.name) + for k, v in self.boxes.iteritems(): + my_string += "%s: %s\n" % (k, str(v)) + self.tw.showlabel('info', my_string) + return + + def undefined_check(self, token): + """ Make sure token has a definition """ + if token.fcn is not None: + return False + if token.name == '%nothing%': + errormsg = '' + else: + errormsg = "%s %s" % (_("I don't know how to"), _(token.name)) + raise logoerror(errormsg) + + def no_args_check(self): + """ Missing argument ? """ + if self.iline and self.iline[0] is not self.symnothing: + return + raise logoerror("#noinput") + + # + # Primitives + # + + def prim_clear(self): + """ Clear screen """ + stop_media(self) + self.tw.canvas.clearscreen() + + 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 = millis()+self.an_int(time*1000) + while millis()<endtime: + yield True + self.tw.active_turtle.hide() + self.ireturn() + yield True + + def prim_repeat(self, num, blklist): + """ Repeat list num times. """ + num = self.an_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) + self.ireturn() + yield True + + def prim_list(self, blklist): + """ Expandable list block """ + self.show_list(blklist) + self.ireturn() + yield True + + def myfunction(self, f, x): + """ Programmable block """ + y = myfunc(f, x) + if y == None: + stop_logo(self.tw) + raise logoerror("#syntaxerror") + else: + return y + + 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 + + def prim_define(self, name, body): + """ Define a primitive """ + if type(name) is not self.symtype: + name = self.intern(name) + name.nargs, name.fcn = 0, body + name.rprim = True + + 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 (not self.stacks.has_key('stack3'+str(x))) or\ + self.stacks['stack3'+str(x)] is None: + raise logoerror("#nostack") + self.icall(self.evline, self.stacks['stack3'+str(x)][:]) + yield True + self.procstop = False + self.ireturn() + yield True + + def prim_stack1(self): + """ Process Stack 1 """ + if self.stacks['stack1'] is None: + raise logoerror("#nostack") + self.icall(self.evline, self.stacks['stack1'][:]) + yield True + self.procstop = False + self.ireturn() + yield True + + def prim_stack2(self): + """ Process Stack 2 """ + if self.stacks['stack2'] is None: + raise logoerror("#nostack") + self.icall(self.evline, self.stacks['stack2'][:]) + yield True + self.procstop = False + 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', self.heap) + + def an_int(self, n): + """ Raise an error if n doesn't convert to int. """ + if type(n) == int: + return n + elif type(n) == float: + return int(n) + elif type(n) == str: + return int(ord(n[0])) + else: + 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: + raise logoerror("#emptybox") + + def prim_myblock(self, x): + """ Run Python code imported from Journal """ + if self.tw.myblock is not None: + try: + if len(x) == 1: + y = myfunc_import(self, self.tw.myblock, x[0]) + else: + y = myfunc_import(self, self.tw.myblock, x) + except: + raise logoerror("#nocode") + else: + raise logoerror("#nocode") + return + + def prim_print(self, n, flag): + """ Print 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_': + try: + if self.tw.running_sugar: + dsobject = datastore.get(n[6:]) + self.tw.showlabel('status', dsobject.metadata['title']) + dsobject.destroy() + else: + self.tw.showlabel('status', n[6:]) + except: + 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', round_int(n)) + + 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: + self.keyboard = 0 + self.tw.keypress = "" + + def prim_setbox(self, name, x, val): + """ Define value of named box """ + if x is None: + self.boxes[name] = val + else: + if type(convert(x, float, False)) == float: + if int(float(x)) == x: + x = int(x) + self.boxes[name+str(x)] = val + + def prim_push(self, val): + """ Push value onto FILO """ + self.heap.append(val) + + def prim_pop(self): + """ Pop value off of FILO """ + try: + return self.heap.pop(-1) + except: + raise logoerror ("#emptyheap") + + 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 + y = self.tw.canvas.ycor/self.tw.coord_scale + for s in sarray: + self.tw.canvas.setxy(x, y) + 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 show(self, string, center=False): + """ Show is the general-purpose media-rendering block. """ + # convert from Turtle coordinates to screen coordinates + x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) + y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) + if type(string) == str or type(string) == unicode: + if string == "media_None": + pass + elif string[0:6] == 'media_': + self.insert_image(string, center) + elif string[0:6] == 'descr_': + self.insert_desc(string) + elif string[0:6] == 'audio_': + self.play_sound(string) + else: + 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) + 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, media, center): + """ Image only (at current x, y) """ + w = (self.tw.canvas.width * self.scale)/100 + h = (self.tw.canvas.height * self.scale)/100 + # convert from Turtle coordinates to screen coordinates + x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) + y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) + if center: + x -= w/2 + y -= h/2 + if media[0:5] == 'media': + self.show_picture(media, x, y, w, h) + + def insert_desc(self, media): + """ Description text only (at current x, y) """ + w = (self.tw.canvas.width * self.scale)/100 + h = (self.tw.canvas.height * self.scale)/100 + # convert from Turtle coordinates to screen coordinates + x = self.tw.canvas.width/2+int(self.tw.canvas.xcor) + y = self.tw.canvas.height/2-int(self.tw.canvas.ycor) + if media[0:5] == 'descr': + self.show_description(media, x, y, w, h) + + def play_sound(self, audio): + """ Sound file from Journal """ + if audio == "" or audio[6:] == "": + raise logoerror("#nomedia") + if self.tw.running_sugar: + if audio[6:] != "None": + try: + dsobject = datastore.get(audio[6:]) + play_audio(self, dsobject.file_path) + except: + print "Couldn't open id: " + str(audio[6:]) + else: + play_audio(self, audio[6:]) + + def show_picture(self, media, x, y, w, h): + """ Image file from Journal """ + if media == "" or media[6:] == "": + pass + elif media[6:] is not "None": + pixbuf = None + self.filepath = None + if self.tw.running_sugar: + try: + dsobject = datastore.get(media[6:]) + if movie_media_type(dsobject.file_path): + play_movie_from_file(self, dsobject.file_path, + int(x), int(y), int(w), int(h)) + else: + self.filepath = dsobject.file_path + pixbuf = get_pixbuf_from_journal(dsobject, + int(w), int(h)) + dsobject.destroy() + except: + # Maybe it is a pathname instead. + try: + self.filepath = media[6:0] + pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( + media[6:], int(w), int(h)) + except: + self.filepath = None + self.tw.showlabel('nojournal', media[6:]) + print "Couldn't open Journal object %s" % (media[6:]) + else: + try: + if movie_media_type(media): + play_movie_from_file(self, media[6:], int(x), int(y), + int(w), int(h)) + else: + self.filepath = media[6:] + pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( + media[6:], int(w), int(h)) + except: + self.filepath = None + self.tw.showlabel('nofile', media[6:]) + print "Couldn't open media object %s" % (media[6:]) + if pixbuf is not None: + self.tw.canvas.draw_pixbuf(pixbuf, 0, 0, int(x), int(y), + int(w), int(h), + self.filepath) + + def show_description(self, media, x, y, w, h): + """ Description field from Journal """ + if media == "" or media[6:] == "": + return + elif media[6:] != "None": + text = None + if self.tw.running_sugar: + try: + dsobject = datastore.get(media[6:]) + # TODO: handle rtf, pdf, etc. (See #893) + if text_media_type(dsobject.file_path): + f = open(dsobject.file_path, 'r') + text = f.read() + f.close() + else: + text = str(dsobject.metadata['description']) + dsobject.destroy() + except: + print "no description in %s" % (media[6:]) + else: + try: + f = open(media[6:], 'r') + text = f.read() + f.close() + except: + print "no text in %s?" % (media[6:]) + if text is not None: + self.tw.canvas.draw_text(text, int(x), int(y), + self.body_height, int(w)) + + # Depreciated block methods + + def draw_title(self, title, x, y): + """ slide title """ + self.tw.canvas.draw_text(title, int(x), int(y), + self.title_height, + self.tw.canvas.width-x) + + 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) + # 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) + self.show(media) + if self.tw.running_sugar: + x = 0 + self.tw.canvas.setxy(x, y) + 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) + # 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) + self.show(media1) + x = 0 + self.tw.canvas.setxy(x, y) + self.show(media2) + y = -self.title_height + if self.tw.running_sugar: + self.tw.canvas.setxy(x, y) + self.show(media2.replace("media_","descr_")) + x = -(self.tw.canvas.width/2) + xo + self.tw.canvas.setxy(x, y) + 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) + # 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) + 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) + # 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) + self.show(media1) + if self.tw.running_sugar: + x = 0 + self.tw.canvas.setxy(x, y) + self.show(media1.replace("media_","descr_")) + y = -self.title_height + self.tw.canvas.setxy(x, y) + self.show(media2.replace("media_","descr_")) + x = -(self.tw.canvas.width/2) + xo + self.tw.canvas.setxy(x, y) + 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) + # 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) + self.show(media1) + x = 0 + self.tw.canvas.setxy(x, y) + self.show(media2) + y = -self.title_height + self.tw.canvas.setxy(x, y) + self.show(media4) + x = -(self.tw.canvas.width/2) + xo + self.tw.canvas.setxy(x, y) + 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) + # 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) + 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) |