Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/talogo.py
diff options
context:
space:
mode:
Diffstat (limited to 'TurtleArt/talogo.py')
-rw-r--r--TurtleArt/talogo.py1366
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)