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.py629
1 files changed, 539 insertions, 90 deletions
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index 0b178c6..775af0f 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -22,9 +22,12 @@
#THE SOFTWARE.
import gtk
+import gobject
from time import time, sleep
from operator import isNumberType
+import os
+from os.path import exists as os_path_exists
from UserDict import UserDict
try:
@@ -33,10 +36,17 @@ try:
except ImportError:
GRID_CELL_SIZE = 55
-from taconstants import (TAB_LAYER, DEFAULT_SCALE, PREFIX_DICTIONARY)
+import traceback
+
+from tablock import (Block, Media, media_blocks_dictionary)
+from taconstants import (TAB_LAYER, DEFAULT_SCALE, ICON_SIZE)
+from tajail import (myfunc, myfunc_import)
from tapalette import (block_names, value_blocks)
-from tautils import (get_pixbuf_from_journal, convert, data_from_file,
- text_media_type, round_int, debug_output, find_group)
+from tatype import (TATypeError, TYPES_NUMERIC)
+from tautils import (get_pixbuf_from_journal, data_from_file, get_stack_name,
+ text_media_type, round_int, debug_output, find_group,
+ get_path, image_to_base64, data_to_string, data_to_file,
+ get_load_name, chooser_dialog)
try:
from util.RtfParser import RtfTextOnly
@@ -46,7 +56,6 @@ except ImportError:
from gettext import gettext as _
-media_blocks_dictionary = {} # new media blocks get added here
primitive_dictionary = {} # new block primitives get added here
@@ -79,7 +88,21 @@ class logoerror(Exception):
return str(self.value)
-class HiddenBlock:
+class NegativeRootError(BaseException):
+ """ Similar to the ZeroDivisionError, this error is raised at runtime
+ when trying to computer the square root of a negative number. """
+
+ DEFAULT_MESSAGE = 'square root of negative number'
+
+ def __init__(self, neg_value=None, message=DEFAULT_MESSAGE):
+ self.neg_value = neg_value
+ self.message = message
+
+ def __str__(self):
+ return str(self.message)
+
+
+class HiddenBlock(Block):
def __init__(self, name, value=None):
self.name = name
@@ -92,6 +115,7 @@ class HiddenBlock:
self.connections = []
self.docks = []
+
# Utility functions
@@ -142,7 +166,6 @@ class LogoCode:
self.hidden_turtle = None
- self.keyboard = 0
self.trace = 0
self.update_values = False
self.gplay = None
@@ -187,6 +210,14 @@ class LogoCode:
self.oblist[string] = sym
return sym
+ def get_prim_callable(self, name):
+ """ Return the callable primitive associated with the given name """
+ sym = self.oblist.get(name)
+ if sym is not None:
+ return sym.fcn
+ else:
+ return None
+
def run_blocks(self, code):
"""Run code generated by generate_code().
"""
@@ -234,27 +265,17 @@ class LogoCode:
blk = action_blk
for b in blocks:
- if b.name == 'hat1':
- code = self._blocks_to_code(b)
- self.stacks['stack1'] = self._readline(code)
- elif b.name == 'hat2':
- code = self._blocks_to_code(b)
- self.stacks['stack2'] = self._readline(code)
- elif b.name == 'hat':
- if b.connections is not None and len(b.connections) > 1 and \
- b.connections[1] is not None:
+ if b.name in ('hat', 'hat1', 'hat2'):
+ stack_name = get_stack_name(b)
+ if stack_name:
+ stack_key = self._get_stack_key(stack_name)
code = self._blocks_to_code(b)
- try:
- x = b.connections[1].values[0]
- except IndexError:
- self.tw.showlabel('#nostack')
- self.tw.showblocks()
- self.tw.running_blocks = False
- return None
- if isinstance(convert(x, float, False), float):
- if int(float(x)) == x:
- x = int(x)
- self.stacks['stack3' + str(x)] = self._readline(code)
+ self.stacks[stack_key] = self._readline(code)
+ else:
+ self.tw.showlabel('#nostack')
+ self.tw.showblocks()
+ self.tw.running_blocks = False
+ return None
code = self._blocks_to_code(blk)
@@ -278,7 +299,8 @@ class LogoCode:
return ['%nothing%', '%nothing%']
code = []
dock = blk.docks[0]
- if len(dock) > 4: # There could be a '(', ')', '[' or ']'.
+ # There could be a '(', ')', '[' or ']'.
+ if len(dock) > 4 and dock[4] in ('[', ']', ']['):
code.append(dock[4])
if blk.primitive is not None: # make a tuple (prim, blk)
if blk in self.tw.block_list.list:
@@ -286,37 +308,20 @@ class LogoCode:
self.tw.block_list.list.index(blk)))
else:
code.append(blk.primitive) # Hidden block
- 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': # deprecated block
- if isinstance(blk.values[0], (float, 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 in PREFIX_DICTIONARY:
- if blk.values[0] is not None:
- code.append(PREFIX_DICTIONARY[blk.name] +
- str(blk.values[0]))
- else:
- code.append(PREFIX_DICTIONARY[blk.name] + 'None')
- elif blk.name in media_blocks_dictionary:
- code.append('#smedia_' + blk.name.upper())
- else:
+ elif blk.is_value_block(): # Extract the value from content blocks.
+ value = blk.get_value()
+ if value is None:
return ['%nothing%']
+ else:
+ code.append(value)
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 ']'.
+ # There could be a '(', ')', '[' or ']'.
+ if len(dock) > 4 and dock[4] in ('[', ']', ']['):
for c in dock[4]:
code.append(c)
if b is not None:
@@ -346,7 +351,9 @@ class LogoCode:
bindex = None
if isinstance(token, tuple):
(token, bindex) = token
- if isNumberType(token):
+ if isinstance(token, Media):
+ res.append(token)
+ elif isNumberType(token):
res.append(token)
elif token.isdigit():
res.append(float(token))
@@ -401,7 +408,7 @@ class LogoCode:
self.istack.append(self.step)
self.step = fcn(*(args))
- def evline(self, blklist):
+ def evline(self, blklist, call_me=True):
""" Evaluate a line of code from the list. """
oldiline = self.iline
self.iline = blklist[:]
@@ -432,7 +439,7 @@ class LogoCode:
(token, self.bindex) = self.iline[1]
# Process the token and any arguments.
- self.icall(self._eval)
+ self.icall(self._eval, call_me)
yield True
# Time to unhighlight the current block.
@@ -455,7 +462,7 @@ class LogoCode:
self.tw.display_coordinates()
yield True
- def _eval(self):
+ def _eval(self, call_me=True):
""" Evaluate the next token on the line of code we are processing. """
token = self.iline.pop(0)
bindex = None
@@ -467,7 +474,7 @@ class LogoCode:
# We highlight blocks here in case an error occurs...
if not self.tw.hide and bindex is not None:
self.tw.block_list.list[bindex].highlight()
- self.icall(self._evalsym, token)
+ self.icall(self._evalsym, token, call_me)
yield True
# and unhighlight if everything was OK.
if not self.tw.hide and bindex is not None:
@@ -479,7 +486,7 @@ class LogoCode:
self.ireturn(res)
yield True
- def _evalsym(self, token):
+ def _evalsym(self, token, call_me):
""" Process primitive associated with symbol token """
self._undefined_check(token)
oldcfun, oldarglist = self.cfun, self.arglist
@@ -489,35 +496,53 @@ class LogoCode:
self.tw.showblocks()
self.tw.display_coordinates()
raise logoerror("#noinput")
+ is_Primitive = type(self.cfun.fcn).__name__ == 'Primitive'
+ is_PrimitiveDisjunction = type(self.cfun.fcn).__name__ == \
+ 'PrimitiveDisjunction'
+ call_args = not (is_Primitive or is_PrimitiveDisjunction)
for i in range(token.nargs):
self._no_args_check()
- self.icall(self._eval)
+ self.icall(self._eval, call_args)
yield True
self.arglist.append(self.iresult)
+ need_to_pop_istack = False
if self.cfun.rprim:
if isinstance(self.cfun.fcn, list):
# debug_output('evalsym rprim list: %s' % (str(token)),
# self.tw.running_sugar)
- self.icall(self._ufuncall, self.cfun.fcn)
+ self.icall(self._ufuncall, self.cfun.fcn, call_args)
yield True
+ need_to_pop_istack = True
+ result = None
else:
- self.icall(self.cfun.fcn, *self.arglist)
- yield True
- result = None
+ if call_me:
+ self.icall(self.cfun.fcn, *self.arglist)
+ yield True
+ need_to_pop_istack = True
+ result = None
+ else:
+ result = (self.cfun.fcn, ) + tuple(self.arglist)
else:
- result = self.cfun.fcn(self, *self.arglist)
+ need_to_pop_istack = True
+ if call_me:
+ result = self.cfun.fcn(self, *self.arglist)
+ else:
+ result = (self.cfun.fcn, self) + tuple(self.arglist)
self.cfun, self.arglist = oldcfun, oldarglist
if self.arglist is not None and result is None:
self.tw.showblocks()
raise logoerror("%s %s %s" %
(oldcfun.name, _("did not output to"),
self.cfun.name))
- self.ireturn(result)
- yield True
+ if need_to_pop_istack:
+ self.ireturn(result)
+ yield True
+ else:
+ self.iresult = result
- def _ufuncall(self, body):
+ def _ufuncall(self, body, call_me):
""" ufuncall """
- self.ijmp(self.evline, body)
+ self.ijmp(self.evline, body, call_me)
yield True
def doevalstep(self):
@@ -526,7 +551,9 @@ class LogoCode:
try:
while (_millisecond() - starttime) < 120:
try:
- if self.step is not None:
+ if self.step is None:
+ return False
+ if self.tw.running_turtleart:
try:
self.step.next()
except ValueError:
@@ -534,23 +561,60 @@ class LogoCode:
self.tw.running_sugar)
self.tw.running_blocks = False
return False
+ except TATypeError as tte:
+ # TODO insert the correct block name
+ # (self.cfun.name is only the name of the
+ # outermost block in this statement/ line of code)
+ # use logoerror("#notanumber") when possible
+ if (tte.req_type in TYPES_NUMERIC and
+ tte.bad_type not in TYPES_NUMERIC):
+ raise logoerror("#notanumber")
+ else:
+ raise logoerror(
+ "%s %s %s %s" %
+ (self.cfun.name, _("doesn't like"),
+ str(tte.bad_value), _("as input")))
+ except ZeroDivisionError:
+ raise logoerror("#zerodivide")
+ except NegativeRootError:
+ raise logoerror("#negroot")
+ except IndexError:
+ raise logoerror("#emptyheap")
else:
- return False
+ try:
+ self.step.next()
+ except BaseException as error:
+ if isinstance(error, (StopIteration,
+ logoerror)):
+ raise error
+ else:
+ traceback.print_exc()
+ self.tw.showlabel(
+ 'status', '%s: %s' %
+ (type(error).__name__, str(error)))
+ return False
except StopIteration:
- # self.tw.turtles.show_all()
- if self.hidden_turtle is not None:
- self.hidden_turtle.show()
- self.hidden_turtle = None
+ if self.tw.running_turtleart:
+ # self.tw.turtles.show_all()
+ if self.hidden_turtle is not None:
+ self.hidden_turtle.show()
+ self.hidden_turtle = None
+ else:
+ self.tw.turtles.get_active_turtle().show()
+ self.tw.running_blocks = False
+ return False
else:
- self.tw.turtles.get_active_turtle().show()
- self.tw.running_blocks = False
- return False
+ self.ireturn()
except logoerror, e:
- self.tw.showblocks()
- self.tw.display_coordinates()
- self.tw.showlabel('syntaxerror', str(e))
- self.tw.turtles.show_all()
- self.tw.running_blocks = False
+ if self.tw.running_turtleart:
+ self.tw.showblocks()
+ self.tw.display_coordinates()
+ self.tw.showlabel('syntaxerror', str(e))
+ self.tw.turtles.show_all()
+ self.tw.running_blocks = False
+ else:
+ traceback.print_exc()
+ self.tw.showlabel('status', 'logoerror: ' + str(e))
return False
return True
@@ -597,19 +661,265 @@ class LogoCode:
name.nargs, name.fcn = 0, body
name.rprim = True
+ def prim_start(self, *ignored_args):
+ ''' Start block: recenter '''
+ if self.tw.running_sugar:
+ self.tw.activity.recenter()
+
def prim_clear(self):
""" Clear screen """
self.tw.clear_plugins()
+ self.stop_playing_media()
+ self.reset_scale()
+ self.reset_timer()
+ self.clear_value_blocks()
+ self.reset_internals()
+ self.tw.canvas.clearscreen()
+ self.tw.turtles.reset_turtles()
+
+ def stop_playing_media(self):
if self.tw.gst_available:
from tagplay import stop_media
stop_media(self)
- self.tw.canvas.clearscreen()
- self.tw.turtles.reset_turtles()
+
+ def reset_scale(self):
self.scale = DEFAULT_SCALE
- self.hidden_turtle = None
+
+ def reset_timer(self):
self.start_time = time()
- self.clear_value_blocks()
- self.tw.activity.restore_state()
+
+ def get_start_time(self):
+ return self.start_time
+
+ def reset_internals(self):
+ self.hidden_turtle = None
+ if self.tw.running_turtleart:
+ self.tw.activity.restore_state()
+
+ def prim_loop(self, controller, blklist):
+ """ Execute a loop
+ controller -- iterator that yields True iff the loop should be run
+ once more OR a callable that returns such an iterator
+ blklist -- list of callables that form the loop body """
+ if not hasattr(controller, "next"):
+ if callable(controller):
+ controller = controller()
+ else:
+ raise TypeError("a loop controller must be either an iterator "
+ "or a callable that returns an iterator")
+ while next(controller):
+ self.icall(self.evline, blklist[:])
+ yield True
+ if self.procstop:
+ break
+ self.ireturn()
+ yield True
+
+ def prim_clamp(self, blklist):
+ """ Run clamp blklist """
+ self.icall(self.evline, blklist[:])
+ yield True
+ self.procstop = False
+ self.ireturn()
+ yield True
+
+ def set_scale(self, scale):
+ ''' Set scale for media blocks '''
+ self.scale = scale
+
+ def get_scale(self):
+ ''' Set scale for media blocks '''
+ return self.scale
+
+ def prim_stop_stack(self):
+ """ Stop execution of a stack """
+ self.procstop = True
+
+ def prim_turtle(self, name):
+ self.tw.turtles.set_turtle(name)
+
+ def prim_wait(self, wait_time):
+ """ Show the turtle while we wait """
+ self.tw.turtles.get_active_turtle().show()
+ endtime = _millisecond() + wait_time * 1000.
+ while _millisecond() < endtime:
+ sleep(wait_time / 10.)
+ yield True
+ self.tw.turtles.get_active_turtle().hide()
+ self.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_set_box(self, name, value):
+ """ Store value in named box """
+ (key, is_native) = self._get_box_key(name)
+ self.boxes[key] = value
+ if is_native:
+ if self.update_values:
+ self.update_label_value(name, value)
+ else:
+ if self.update_values:
+ self.update_label_value('box', value, label=name)
+
+ def prim_get_box(self, name):
+ """ Retrieve value from named box """
+ (key, is_native) = self._get_box_key(name)
+ try:
+ return self.boxes[key]
+ except KeyError:
+ # FIXME this looks like a syntax error in the GUI
+ raise logoerror("#emptybox")
+
+ def _get_box_key(self, name):
+ """ Return the key used for this box in the boxes dictionary and a
+ boolean indicating whether it is a 'native' box """
+ if name in ('box1', 'box2'):
+ return (name, True)
+ else:
+ # make sure '5' and '5.0' point to the same box
+ if isinstance(name, (basestring, int, long)):
+ try:
+ name = float(name)
+ except ValueError:
+ pass
+ return ('box3_' + str(name), False)
+
+ def prim_define_stack(self, name):
+ """ Top of a named stack """
+ pass
+
+ def prim_invoke_stack(self, name):
+ """ Process a named stack """
+ key = self._get_stack_key(name)
+ if self.stacks.get(key) is None:
+ raise logoerror("#nostack")
+ self.icall(self.evline, self.stacks[key][:])
+ yield True
+ self.procstop = False
+ self.ireturn()
+ yield True
+
+ def _get_stack_key(self, name):
+ """ Return the key used for this stack in the stacks dictionary """
+ if name in ('stack1', 'stack2'):
+ return name
+ else:
+ # make sure '5' and '5.0' point to the same action stack
+ if isinstance(name, (int, long, float)):
+ if int(name) == name:
+ name = int(name)
+ else:
+ name = float(name)
+ return 'stack3' + str(name)
+
+ def load_heap(self, path):
+ """ Load FILO from file """
+ if self.tw.running_sugar:
+ # Choose a datastore object and push data to heap (Sugar only)
+ chooser_dialog(self.tw.parent, path, self.push_file_data_to_heap)
+ else:
+ if not os.path.exists(path):
+ path, self.tw.load_save_folder = get_load_name(
+ '.*', self.tw.load_save_folder)
+ if path is None:
+ return
+
+ data = data_from_file(path)
+ if data is not None:
+ for val in data:
+ self.heap.append(val)
+
+ def save_heap(self, path):
+ """ save FILO to file """
+ if self.tw.running_sugar:
+ from sugar import profile
+ from sugar.datastore import datastore
+ from sugar.activity import activity
+
+ # Save JSON-encoded heap to temporary file
+ heap_file = os.path.join(get_path(activity, 'instance'),
+ str(path) + '.txt')
+ data_to_file(self.heap, heap_file)
+
+ # Create a datastore object
+ dsobject = datastore.create()
+
+ # Write any metadata (specifically set the title of the file
+ # and specify that this is a plain text file).
+ dsobject.metadata['title'] = str(path)
+ dsobject.metadata['icon-color'] = profile.get_color().to_string()
+ dsobject.metadata['mime_type'] = 'text/plain'
+ dsobject.set_file_path(heap_file)
+ datastore.write(dsobject)
+ dsobject.destroy()
+ else:
+ heap_file = path
+ data_to_file(self.heap, heap_file)
+
+ def get_heap(self):
+ return self.heap
+
+ def reset_heap(self):
+ """ Reset heap to an empty list """
+ # empty the list rather than setting it to a new empty list object,
+ # so the object references are preserved
+ while self.heap:
+ self.heap.pop()
+
+ def prim_myblock(self, *args):
+ """ Run Python code imported from Journal """
+ if self.bindex is not None and self.bindex in self.tw.myblock:
+ try:
+ myfunc_import(self, self.tw.myblock[self.bindex], args)
+ except:
+ raise logoerror("#syntaxerror")
+
+ def prim_myfunction(self, f, *args):
+ """ Programmable block (Call tajail.myfunc and convert any errors to
+ logoerrors) """
+ try:
+ y = myfunc(f, args)
+ 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 clear_value_blocks(self):
if not hasattr(self, 'value_blocks_to_update'):
@@ -686,6 +996,145 @@ class LogoCode:
for blk in drag_group:
blk.spr.move_relative((dx, 0))
+ def reskin(self, obj):
+ """ 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
+ self.dsobject = None
+
+ if os_path_exists(obj.value): # file path
+ self.filepath = obj.value
+ elif self.tw.running_sugar: # datastore object
+ from sugar.datastore import datastore
+ try:
+ self.dsobject = datastore.get(obj.value)
+ except:
+ debug_output("Couldn't find dsobject %s" %
+ (obj.value), self.tw.running_sugar)
+ if self.dsobject is not None:
+ self.filepath = self.dsobject.file_path
+
+ if self.filepath is 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.turtles.get_active_turtle().set_shapes([pixbuf])
+ pen_state = self.tw.turtles.get_active_turtle().get_pen_state()
+ if pen_state:
+ self.tw.turtles.get_active_turtle().set_pen_state(False)
+ self.tw.turtles.get_active_turtle().forward(0)
+ if pen_state:
+ self.tw.turtles.get_active_turtle().set_pen_state(True)
+
+ if self.tw.sharing():
+ if self.tw.running_sugar:
+ tmp_path = get_path(self.tw.activity, 'instance')
+ else:
+ tmp_path = '/tmp'
+ tmp_file = os.path.join(get_path(self.tw.activity, 'instance'),
+ 'tmpfile.png')
+ pixbuf.save(tmp_file, 'png', {'quality': '100'})
+ data = image_to_base64(tmp_file, tmp_path)
+ height = pixbuf.get_height()
+ width = pixbuf.get_width()
+ event = 'R|%s' % (data_to_string([self.tw.nick,
+ [round_int(width),
+ round_int(height),
+ data]]))
+ gobject.idle_add(self.tw.send_event, event)
+ os.remove(tmp_file)
+
+ def showlist(self, objects):
+ """ Display list of media objects """
+ x = (self.tw.turtles.get_active_turtle().get_xy()[0] /
+ self.tw.coord_scale)
+ y = (self.tw.turtles.get_active_turtle().get_xy()[1] /
+ self.tw.coord_scale)
+ for obj in objects:
+ self.tw.turtles.get_active_turtle().set_xy(x, y, pendown=False)
+ self.show(obj)
+ y -= int(self.tw.canvas.textsize * self.tw.lead)
+
+ def show(self, obj, center=False):
+ """ Show is the general-purpose media-rendering block. """
+ # media
+ if isinstance(obj, Media) and obj.value:
+ self.filepath = None
+ self.pixbuf = None # Camera writes directly to pixbuf
+ self.dsobject = None
+
+ # camera snapshot
+ if obj.value.lower() in media_blocks_dictionary:
+ media_blocks_dictionary[obj.value.lower()]()
+ # file path
+ elif os_path_exists(obj.value):
+ self.filepath = obj.value
+ # datastore object
+ elif self.tw.running_sugar:
+ from sugar.datastore import datastore
+ try:
+ self.dsobject = datastore.get(obj.value)
+ except:
+ debug_output("Couldn't find dsobject %s" %
+ (obj.value), self.tw.running_sugar)
+ if self.dsobject is not None:
+ self.filepath = self.dsobject.file_path
+
+ if self.pixbuf is not None:
+ self.insert_image(center=center, pixbuf=True)
+ elif self.filepath is None:
+ if self.dsobject is not None:
+ self.tw.showlabel(
+ 'nojournal',
+ self.dsobject.metadata['title'])
+ else:
+ self.tw.showlabel('nojournal', obj.value)
+ debug_output("Couldn't open %s" % (obj.value),
+ self.tw.running_sugar)
+ elif obj.type == 'media':
+ self.insert_image(center=center)
+ elif obj.type == '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 obj.type == 'audio':
+ self.play_sound()
+ elif obj.type == 'video':
+ self.play_video()
+
+ if self.dsobject is not None:
+ self.dsobject.destroy()
+
+ # text or number
+ elif isinstance(obj, (basestring, float, int)):
+ if isinstance(obj, (float, int)):
+ obj = round_int(obj)
+ x, y = self.x2tx(), self.y2ty()
+ if center:
+ y -= self.tw.canvas.textsize
+ self.tw.turtles.get_active_turtle().draw_text(
+ obj, x, y,
+ int(self.tw.canvas.textsize * self.scale / 100.),
+ self.tw.canvas.width - x)
+
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)
@@ -861,7 +1310,7 @@ class LogoCode:
def _expand_forever(self, b, blk, blocks):
""" Expand a while or until block into: forever, ifelse, stopstack
- Expand a forever block to run in a separate stack
+ Expand a forever block to run in a separate stack
Parameters: the loop block, the top block, all blocks.
Return the start block of the expanded loop, and all blocks."""
@@ -911,7 +1360,7 @@ class LogoCode:
first_label_blk = HiddenBlock('string', value=action_flow_name)
# Assign new connections and build the docks
- if inflow is not None:
+ if inflow is not None and b in inflow.connections:
i = inflow.connections.index(b)
if until_blk and whileflow is not None:
inflow.connections[i] = action_first
@@ -980,14 +1429,14 @@ class LogoCode:
# Create a separate stacks for the forever loop and the whileflow
code = self._blocks_to_code(forever_blk)
- self.stacks['stack3' + str(action_name)] = self._readline(code)
+ self.stacks[self._get_stack_key(action_name)] = self._readline(code)
if until_blk and whileflow is not None:
# Create a stack from the whileflow to be called from
# action_first, but then reconnect it to the ifelse block
c = whileflow.connections[0]
whileflow.connections[0] = None
code = self._blocks_to_code(whileflow)
- self.stacks['stack3' + str(action_flow_name)] = \
+ self.stacks[self._get_stack_key(action_flow_name)] = \
self._readline(code)
whileflow.connections[0] = c