Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPootle daemon <pootle@pootle.sugarlabs.org>2013-12-11 05:30:31 (GMT)
committer Pootle daemon <pootle@pootle.sugarlabs.org>2013-12-11 05:30:31 (GMT)
commit37922d95520efc3715927a8886021642d928f04b (patch)
tree5c0caa14d8ce16d35072de149e7bdc005717f9b8
parent7f92784e77073ea9679b534852b8d09dc4e41a43 (diff)
parent7675249cff03e9c52a1dc58f46da761ebfee85b5 (diff)
Merge branch 'master' of git.sugarlabs.org:turtleart/mainline
-rw-r--r--NEWS1
-rw-r--r--TurtleArt/tablock.py37
-rw-r--r--TurtleArt/taconstants.py2
-rw-r--r--TurtleArt/talogo.py70
-rw-r--r--TurtleArt/tapalette.py2
-rwxr-xr-xTurtleArt/tasprite_factory.py86
-rw-r--r--TurtleArt/tawindow.py22
-rw-r--r--plugins/turtle_blocks_extras/turtle_blocks_extras.py15
-rw-r--r--samples/game-snake.tb51
-rw-r--r--samples/math-prime-factors.ta97
10 files changed, 256 insertions, 127 deletions
diff --git a/NEWS b/NEWS
index b02eb3b..730b50f 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,7 @@ ENHANCEMENTS:
* Add load/save plugin dialog to GNOME version (Daniel Francis)
* Add busy cursor when projects are being prepared to run
* Reworked Duplicate Blocks warning graphic to reflect current block shapes
+* Refactor until block shape to better reflect flow logic
* New translations
BUG FIX:
diff --git a/TurtleArt/tablock.py b/TurtleArt/tablock.py
index cd5515e..3b9650f 100644
--- a/TurtleArt/tablock.py
+++ b/TurtleArt/tablock.py
@@ -209,7 +209,7 @@ class Block:
self._visible = True
self.unknown = False # Block is of unknown style
- self.block_methods = {
+ self._block_methods = {
'basic-style': self._make_basic_style,
'blank-style': self._make_blank_style,
'basic-style-head': self._make_basic_style_head,
@@ -241,6 +241,7 @@ class Block:
'clamp-style-collapsed': self._make_clamp_style_collapsed,
'clamp-style-1arg': self._make_clamp_style_1arg,
'clamp-style-boolean': self._make_clamp_style_boolean,
+ 'clamp-style-until': self._make_clamp_style_until,
'clamp-style-else': self._make_clamp_style_else,
'flow-style-tail': self._make_flow_style_tail,
'portfolio-style-2x2': self._make_portfolio_style_2x2,
@@ -679,7 +680,8 @@ class Block:
y = self.docks[1][3] - int(int(self.font_size[0] * 1.3))
self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
True, 'right', y_pos=y, i=0)
- elif self.name in block_styles['clamp-style-boolean']:
+ elif self.name in block_styles['clamp-style-boolean'] or \
+ self.name in block_styles['clamp-style-until']:
y = self.docks[1][3] - int(int(self.font_size[0] * 1.3))
self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
True, 'right', y_pos=y, i=0)
@@ -709,19 +711,18 @@ class Block:
self._right = 0
self._bottom = 0
self.svg.set_stroke_width(STANDARD_STROKE_WIDTH)
- self.svg.clear_docks()
if isinstance(self.name, unicode):
self.name = self.name.encode('utf-8')
for k in block_styles.keys():
if self.name in block_styles[k]:
- if isinstance(self.block_methods[k], list):
- self.block_methods[k][0](svg, self.block_methods[k][1],
- self.block_methods[k][2])
+ if isinstance(self._block_methods[k], list):
+ self._block_methods[k][0](svg, self._block_methods[k][1],
+ self._block_methods[k][2])
else:
- self.block_methods[k](svg)
+ self._block_methods[k](svg)
return
error_output('ERROR: block type not found %s' % (self.name))
- self.block_methods['blank-style'](svg)
+ self._block_methods['blank-style'](svg)
self.unknown = True
def _set_colors(self, svg):
@@ -1086,6 +1087,24 @@ class Block:
['flow', False, self.svg.docks[4][0],
self.svg.docks[4][1], ']']]
+ def _make_clamp_style_until(self, svg, extend_x=0, extend_y=4):
+ self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
+ self.svg.set_slot(True)
+ self.svg.set_tab(True)
+ self.svg.set_boolean(True)
+ self.svg.second_clamp(False)
+ self._make_block_graphics(svg, self.svg.clamp_until)
+ # Dock positions are flipped
+ self.docks = [['flow', True, self.svg.docks[0][0],
+ self.svg.docks[0][1]],
+ ['bool', False, self.svg.docks[3][0],
+ self.svg.docks[3][1]],
+ ['flow', False, self.svg.docks[1][0],
+ self.svg.docks[1][1], '['],
+ # Skip bottom of clamp
+ ['flow', False, self.svg.docks[4][0],
+ self.svg.docks[4][1], ']']]
+
def _make_clamp_style_else(self, svg, extend_x=0, extend_y=4):
self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y,
self.dx + self.ex + extend_x, self.ey2 + extend_y)
@@ -1194,6 +1213,7 @@ class Block:
def _make_block_graphics(self, svg, function, arg=None):
self._set_colors(svg)
self.svg.set_gradient(True, GRADIENT_COLOR)
+ self.svg.clear_docks()
if arg is None:
pixbuf = svg_str_to_pixbuf(function())
else:
@@ -1203,6 +1223,7 @@ class Block:
self.shapes[0] = _pixbuf_to_cairo_surface(pixbuf,
self.width, self.height)
self.svg.set_gradient(False)
+ self.svg.clear_docks()
if arg is None:
pixbuf = svg_str_to_pixbuf(function())
else:
diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py
index 78cb9e1..75288c1 100644
--- a/TurtleArt/taconstants.py
+++ b/TurtleArt/taconstants.py
@@ -341,6 +341,8 @@ VOICES = {'af': 'afrikaans', 'cy': 'welsh-test', 'el': 'greek',
MACROS = {
'ifthenelse': # Because it is too big to fit on the palette
[[0, 'ifelse', 0, 0, [None, None, None, None, None]]],
+ 'untilmacro': # Because it is too big to fit on the palette
+ [[0, 'until', 0, 0, [None, None, None, None]]],
'kbinput':
[[0, 'until', 0, 0, [None, 1, 4, None]],
[1, 'greater2', 0, 0, [0, 2, 3, None]],
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index 67aa32c..5792043 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -835,24 +835,35 @@ class LogoCode:
name = float(name)
return 'stack3' + str(name)
- def load_heap(self, path):
+ def load_heap(self, obj):
""" 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)
+ # Is the object a dsobject?
+ if isinstance(obj, Media) and obj.value:
+ from sugar.datastore import datastore
+ try:
+ dsobject = datastore.get(obj.value)
+ except:
+ debug_output("Couldn't find dsobject %s" %
+ (obj.value), self.tw.running_sugar)
+ if dsobject is not None:
+ self.push_file_data_to_heap(dsobject)
+ # Or is it a path?
+ elif os.path.exists(obj):
+ self.push_file_data_to_heap(None, path=obj)
+ else:
+ # Finally try choosing a datastore object
+ chooser_dialog(self.tw.parent, obj,
+ self.push_file_data_to_heap)
else:
- if not os.path.exists(path):
- path, self.tw.load_save_folder = get_load_name(
+ # If you cannot find the file, open a chooser.
+ if not os.path.exists(obj):
+ obj, self.tw.load_save_folder = get_load_name(
'.*', self.tw.load_save_folder)
- if path is None:
- return
+ if obj is not None:
+ self.push_file_data_to_heap(None, path=obj)
- data = data_from_file(path)
- if data is not None:
- for val in data:
- self.heap.append(val)
-
- def save_heap(self, path):
+ def save_heap(self, obj):
""" save FILO to file """
if self.tw.running_sugar:
from sugar import profile
@@ -861,22 +872,23 @@ class LogoCode:
# Save JSON-encoded heap to temporary file
heap_file = os.path.join(get_path(activity, 'instance'),
- str(path) + '.txt')
+ 'heap.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'
+ # Write to an existing or new dsobject
+ if isinstance(obj, Media) and obj.value:
+ dsobject = datastore.get(obj.value)
+ else:
+ dsobject = datastore.create()
+ dsobject.metadata['title'] = str(obj)
+ 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
+ heap_file = obj
data_to_file(self.heap, heap_file)
def get_heap(self):
@@ -1011,7 +1023,7 @@ class LogoCode:
self.filepath = None
self.dsobject = None
- if os_path_exists(obj.value): # file path
+ if obj.value is not None and os_path_exists(obj.value):
self.filepath = obj.value
elif self.tw.running_sugar: # datastore object
from sugar.datastore import datastore
@@ -1172,9 +1184,15 @@ class LogoCode:
int(self.tw.canvas.textsize * self.scale / 100.),
self.tw.canvas.width - x)
- def push_file_data_to_heap(self, dsobject):
+ def push_file_data_to_heap(self, dsobject, path=None):
""" push contents of a data store object (assuming json encoding) """
- data = data_from_file(dsobject.file_path)
+ if dsobject:
+ data = data_from_file(dsobject.file_path)
+ elif path is not None:
+ data = data_from_file(path)
+ else:
+ data = None
+ debug_output("No file to open", self.tw.running_sugar)
if data is not None:
for val in data:
self.heap.append(val)
diff --git a/TurtleArt/tapalette.py b/TurtleArt/tapalette.py
index fd8fac7..2cf568a 100644
--- a/TurtleArt/tapalette.py
+++ b/TurtleArt/tapalette.py
@@ -71,6 +71,7 @@ block_styles = {'basic-style': [],
'clamp-style-collapsed': [],
'clamp-style-1arg': [],
'clamp-style-boolean': [],
+ 'clamp-style-until': [],
'clamp-style-else': [],
'portfolio-style-2x2': [],
'portfolio-style-1x1': [],
@@ -289,6 +290,7 @@ class _ProtoBlock():
'clamp-style-collapsible',
'clamp-style-1arg',
'clamp-style-boolean',
+ 'clamp-style-until',
'clamp-style-else']:
EXPANDABLE_FLOW.append(self._name)
diff --git a/TurtleArt/tasprite_factory.py b/TurtleArt/tasprite_factory.py
index 2bd8993..7f9494c 100755
--- a/TurtleArt/tasprite_factory.py
+++ b/TurtleArt/tasprite_factory.py
@@ -609,6 +609,61 @@ stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
svg += self.footer()
return self.header() + svg
+ def clamp_until(self):
+ ''' Until block is like clamp but docks are flipped '''
+ self.reset_min_max()
+ x = self._stroke_width / 2.0
+ y = self._stroke_width / 2.0 + self._radius
+ self.margins[0] = int((x + self._stroke_width + 0.5) * self._scale)
+ self.margins[1] = int((self._stroke_width + 0.5) * self._scale)
+ self.margins[2] = 0
+ self.margins[3] = 0
+ svg = self.new_path(x, y)
+ svg += self._corner(1, -1)
+ svg += self._do_slot()
+ svg += self._rline_to(self._radius + self._stroke_width, 0)
+ svg += self._rline_to(self._expand_x, 0)
+ xx = self._x
+ svg += self._corner(1, 1, skip=True)
+ svg += self._corner(-1, 1, skip=True)
+ svg += self.line_to(xx, self._y)
+ svg += self._rline_to(-self._expand_x, 0)
+ svg += self._do_tab()
+ svg += self._inverse_corner(-1, 1, 90, 0, 0)
+ svg += self._rline_to(0, self._expand_y)
+ svg += self._inverse_corner(1, 1, 90, 0, 0)
+ svg += self._do_slot()
+ svg += self._rline_to(self._radius, 0)
+ if self._second_clamp:
+ svg += self._corner(-1, 1)
+ svg += self.line_to(xx, self._y)
+ svg += self._rline_to(-self._expand_x, 0)
+ svg += self._do_tab()
+ svg += self._inverse_corner(-1, 1, 90, 0, 0)
+ svg += self._rline_to(0, self._expand_y2)
+ svg += self._inverse_corner(1, 1, 90, 0, 0)
+ svg += self._do_slot()
+ svg += self._rline_to(self._radius, 0)
+ if self._innie[0] is True:
+ svg += self._do_innie()
+ else:
+ self.margins[2] = \
+ int((self._x - self._stroke_width + 0.5) * self._scale)
+ svg += self._rline_to(0, self._radius * 3)
+ if self._bool is True:
+ svg += self._do_boolean()
+ svg += self._corner(-1, 1)
+ svg += self._rline_to(-self._radius - self._stroke_width, 0)
+ svg += self._do_tab()
+ svg += self._corner(-1, -1)
+ svg += self._close_path()
+ self.calc_w_h()
+ svg += self.style()
+ if self._collapsible:
+ svg += self._hide_dot()
+ svg += self.footer()
+ return self.header() + svg
+
def status_block(self, graphic=None):
''' Generate a status block '''
self.reset_min_max()
@@ -950,7 +1005,8 @@ stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
0)
return svg_str
- def _corner(self, sign_x, sign_y, a=90, l=0, s=1, start=True, end=True):
+ def _corner(self, sign_x, sign_y, a=90, l=0, s=1, start=True, end=True,
+ skip=False):
svg_str = ""
if sign_x == 1 and sign_y == -1: # Upper-left corner
self._hide_x = self._x + self._radius + self._stroke_width
@@ -970,7 +1026,7 @@ stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
if start:
if sign_x * sign_y == 1:
svg_str += self._rline_to(sign_x * r2, 0)
- else:
+ elif not skip:
svg_str += self._rline_to(0, sign_y * r2)
x = self._x + sign_x * r2
y = self._y + sign_y * r2
@@ -978,7 +1034,7 @@ stroke-width="3.5" fill="%s" stroke="none" />\n' % (self._stroke)
if end:
if sign_x * sign_y == 1:
svg_str += self._rline_to(0, sign_y * r2)
- else:
+ elif not skip:
svg_str += self._rline_to(sign_x * r2, 0)
return svg_str
@@ -1237,6 +1293,7 @@ def close_file(f):
def generator(datapath):
+ '''
svg = SVG()
f = open_file(datapath, "turtle.svg")
svg.set_scale(2)
@@ -1471,29 +1528,42 @@ def generator(datapath):
close_file(f)
svg = SVG()
- f = open_file(datapath, "clampb.svg")
+ f = open_file(datapath, "clampe.svg")
svg.set_scale(2)
svg.expand(30, 0, 0, 0)
svg.set_slot(True)
svg.set_tab(True)
svg.set_boolean(True)
- svg.second_clamp(False)
+ svg.second_clamp(True)
svg_str = svg.clamp()
f.write(svg_str)
close_file(f)
+ '''
svg = SVG()
- f = open_file(datapath, "clampe.svg")
+ f = open_file(datapath, "clampb.svg")
svg.set_scale(2)
- svg.expand(30, 0, 0, 0)
+ svg.expand(0, 30, 0, 0)
svg.set_slot(True)
svg.set_tab(True)
svg.set_boolean(True)
- svg.second_clamp(True)
+ svg.second_clamp(False)
svg_str = svg.clamp()
f.write(svg_str)
close_file(f)
+ svg = SVG()
+ f = open_file(datapath, "clampu.svg")
+ svg.set_scale(2)
+ svg.expand(0, 30, 0, 0)
+ svg.set_slot(True)
+ svg.set_tab(True)
+ svg.set_boolean(True)
+ svg.second_clamp(False)
+ svg_str = svg.clamp_until()
+ f.write(svg_str)
+ close_file(f)
+
def main():
return 0
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index 2aa8f89..2f0a036 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -2553,8 +2553,9 @@ before making changes to your program'))
if blk is None:
continue
if blk.name in EXPANDABLE_FLOW:
- if blk.name in block_styles['clamp-style-1arg'] or\
- blk.name in block_styles['clamp-style-boolean']:
+ if blk.name in block_styles['clamp-style-1arg'] or \
+ blk.name in block_styles['clamp-style-boolean'] or \
+ blk.name in block_styles['clamp-style-until']:
if blk.connections[2] is not None:
self._resize_clamp(blk, blk.connections[2])
elif blk.name in block_styles['clamp-style']:
@@ -3391,7 +3392,9 @@ before making changes to your program'))
if best_destination.name in \
block_styles['clamp-style-1arg'] or \
best_destination.name in \
- block_styles['clamp-style-boolean']:
+ block_styles['clamp-style-boolean'] or \
+ best_destination.name in \
+ block_styles['clamp-style-until']:
if best_destination_dockn == 2:
self._resize_clamp(best_destination,
self.drag_group[0])
@@ -3492,8 +3495,9 @@ before making changes to your program'))
self._expand_expandable(blk2, blk, dy)
self._cascade_expandable(blk2)
elif c is not None and blk2.name in EXPANDABLE_FLOW:
- if blk2.name in block_styles['clamp-style-1arg'] or\
- blk2.name in block_styles['clamp-style-boolean']:
+ if blk2.name in block_styles['clamp-style-1arg'] or \
+ blk2.name in block_styles['clamp-style-boolean'] or \
+ blk2.name in block_styles['clamp-style-until']:
if c == 2:
self._resize_clamp(blk2, None, c)
elif blk2.name in block_styles['clamp-style'] or \
@@ -3542,12 +3546,18 @@ before making changes to your program'))
drag_group = find_group(blk.connections[-1])
for gblk in drag_group:
gblk.spr.move_relative((0, y2-y1))
- # We may have to move the else clamp group down too.
+ # We may have to move the else clamp group up or down too.
if blk.name in block_styles['clamp-style-else'] and dockn == 2:
if blk.connections[3] is not None:
drag_group = find_group(blk.connections[3])
for gblk in drag_group:
gblk.spr.move_relative((0, y2 - y1))
+ # We may have to move the bool group up or down too.
+ if blk.name in block_styles['clamp-style-until']:
+ if blk.connections[1] is not None:
+ drag_group = find_group(blk.connections[1])
+ for gblk in drag_group:
+ gblk.spr.move_relative((0, y2 - y1))
def _expandable_flow_above(self, blk):
''' Is there an expandable flow block above this one? '''
diff --git a/plugins/turtle_blocks_extras/turtle_blocks_extras.py b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
index 3192021..2bb07dd 100644
--- a/plugins/turtle_blocks_extras/turtle_blocks_extras.py
+++ b/plugins/turtle_blocks_extras/turtle_blocks_extras.py
@@ -93,7 +93,8 @@ boolean operators from Numbers palette'))
True)
palette.add_block('until',
- style='clamp-style-boolean',
+ hidden=True, # Too big to fit on palette
+ style='clamp-style-until',
label=_('until'),
prim_name='until',
default=[None, None],
@@ -115,6 +116,13 @@ boolean operators from Numbers palette'))
ArgSlot(TYPE_OBJECT)]),
True)
+ # macro
+ palette.add_block('untilmacro',
+ style='basic-style-extended-vertical',
+ label=_('until'),
+ help_string=_('do-until-True operator that uses \
+boolean operators from Numbers palette'))
+
palette.add_block('sandwichclamp',
style='clamp-style-collapsible',
label=' ',
@@ -535,7 +543,7 @@ make "tmp first :taheap\nmake "taheap butfirst :taheap\noutput :tmp\nend\n')
last-out heap) to a file'))
self.tw.lc.def_prim('saveheap', 1,
Primitive(self.tw.lc.save_heap,
- arg_descs=[ArgSlot(TYPE_STRING)]))
+ arg_descs=[ArgSlot(TYPE_OBJECT)]))
palette.add_block('loadheap',
style='basic-style-1arg',
@@ -546,8 +554,7 @@ last-out heap) to a file'))
last-out heap) from a file'))
self.tw.lc.def_prim('loadheap', 1,
Primitive(self.tw.lc.load_heap,
- arg_descs=[ArgSlot(TYPE_STRING)],
- return_type=TYPE_STRING,
+ arg_descs=[ArgSlot(TYPE_OBJECT)],
call_afterwards=self.after_push))
palette.add_block('isheapempty2',
diff --git a/samples/game-snake.tb b/samples/game-snake.tb
index aa157c3..32984ef 100644
--- a/samples/game-snake.tb
+++ b/samples/game-snake.tb
@@ -1,4 +1,4 @@
-[[0, ["start", 2.0], 183, 131, [null, 56]],
+[[0, ["start", 2.0], 183, 132, [null, 55]],
[1, "hat", 740, 420, [null, 2, 13]],
[2, ["string", "left"], 798, 432, [1, null]],
[3, "hat", 740, 180, [null, 4, 12]],
@@ -7,7 +7,7 @@
[6, ["string", "left"], 556, 281, [5, null]],
[7, "stack", 498, 323, [5, 8, 9]],
[8, ["string", "right"], 556, 323, [7, null]],
-[9, "forward", 498, 365, [7, 10, 51]],
+[9, "forward", 498, 365, [7, 10, 50]],
[10, ["number", 10], 569, 365, [9, null]],
[11, "kbinput", 498, 239, [33, 5]],
[12, ["vspace", 0], 740, 234, [3, 14]],
@@ -22,39 +22,38 @@
[21, ["number", 10], 816, 342, [20, null]],
[22, "left", 758, 582, [15, 23, null]],
[23, ["number", 10], 816, 582, [22, null]],
-[24, "wait", 201, 537, [35, 25, null]],
-[25, ["number", 0.1], 259, 537, [24, null]],
+[24, "wait", 201, 456, [35, 25, null]],
+[25, ["number", 0.1], 259, 456, [24, null]],
[26, "forward", 1020, 276, [30, 27, 39]],
[27, ["number", 5], 1091, 276, [26, null]],
[28, "back", 1020, 402, [39, 29, 31]],
[29, ["number", 5], 1078, 402, [28, null]],
-[30, "penup", 1020, 234, [49, 26]],
+[30, "penup", 1020, 234, [48, 26]],
[31, "pendown", 1020, 444, [28, null]],
-[32, "showblocks", 183, 597, [47, null]],
+[32, "showblocks", 183, 596, [47, null]],
[33, "hat", 498, 185, [null, 34, 11]],
[34, ["string", "action"], 556, 197, [33, null]],
-[35, "stack", 201, 495, [47, 36, 24]],
-[36, ["string", "action"], 259, 495, [35, null]],
-[37, "setpensize", 183, 303, [57, 38, 54]],
-[38, ["number", 8], 285, 303, [37, null]],
+[35, "stack", 201, 414, [47, 36, 24]],
+[36, ["string", "action"], 259, 414, [35, null]],
+[37, "setpensize", 183, 304, [56, 38, 53]],
+[38, ["number", 8], 285, 304, [37, null]],
[39, ["storein", 0], 1020, 318, [26, 40, 41, 28]],
[40, ["string", "color"], 1088, 318, [39, null]],
[41, "see", 1088, 360, [39, null]],
-[42, ["equal2", 0], 239, 395, [47, 43, 53, null]],
-[43, "box", 295, 395, [42, 44, null]],
-[44, ["string", "color"], 350, 395, [43, null]],
+[42, ["equal2", 0], 239, 496, [47, 43, 52, null]],
+[43, "box", 295, 496, [42, 44, null]],
+[44, ["string", "color"], 350, 496, [43, null]],
[45, ["number", 3], 852, 242, [16, null]],
[46, ["number", 1], 852, 482, [17, null]],
-[47, ["until", 21], 183, 429, [48, 42, 35, 32]],
-[48, ["vspace", 0], 183, 387, [54, 47]],
-[49, "hat", 1020, 180, [null, 50, 30]],
-[50, ["string", "look ahead"], 1078, 192, [49, null]],
-[51, "stack", 498, 407, [9, 52, null]],
-[52, ["string", "look ahead"], 556, 407, [51, null]],
-[53, "red", 295, 437, [42, null]],
-[54, "setcolor", 183, 345, [37, 55, 48]],
-[55, "red", 260, 345, [54, null]],
-[56, "clean", 183, 177, [0, 57]],
-[57, ["storein", 0], 183, 219, [56, 58, 59, 37]],
-[58, ["string", "color"], 251, 219, [57, null]],
-[59, "blue", 251, 261, [57, null]]]
+[47, ["until", 21], 183, 388, [53, 42, 35, 32]],
+[48, "hat", 1020, 180, [null, 49, 30]],
+[49, ["string", "look ahead"], 1078, 192, [48, null]],
+[50, "stack", 498, 407, [9, 51, null]],
+[51, ["string", "look ahead"], 556, 407, [50, null]],
+[52, "red", 295, 538, [42, null]],
+[53, "setcolor", 183, 346, [37, 54, 47]],
+[54, "red", 260, 346, [53, null]],
+[55, "clean", 183, 178, [0, 56]],
+[56, ["storein", 0], 183, 220, [55, 57, 58, 37]],
+[57, ["string", "color"], 251, 220, [56, null]],
+[58, "blue", 251, 262, [56, null]]]
diff --git a/samples/math-prime-factors.ta b/samples/math-prime-factors.ta
index b13ae53..543060a 100644
--- a/samples/math-prime-factors.ta
+++ b/samples/math-prime-factors.ta
@@ -101,7 +101,7 @@
[100, ["storein", 0], 223, 784, [153, 101, 102, 385]],
[101, ["string", "radius"], 291, 784, [100, null]],
[102, ["number", 400], 291, 826, [100, null]],
-[103, ["string", "ii"], 684, 636, [189, null]],
+[103, ["string", "ii"], 719, 884, [189, null]],
[104, "seth", 583, 564, [453, 238, 174]],
[105, ["number", 360], 765, 606, [106, null]],
[106, ["division2", 0], 695, 606, [238, 105, 188]],
@@ -125,16 +125,16 @@
[124, ["string", "number"], 1163, 448, [123, null]],
[125, ["plus2", 0], 960, 364, [119, 121, 122]],
[126, "sandwichclampcollapsed", 900, 354, [115, 119, null]],
-[127, ["until", 62], 463, 710, [136, 132, 451, null]],
-[128, ["storein", 20], 481, 818, [451, 186, 236, null]],
-[129, ["string", "ii"], 603, 818, [186, null]],
-[130, "box", 603, 942, [236, 187, null]],
-[131, ["string", "ii"], 712, 942, [187, null]],
-[132, ["equal2", 20], 519, 636, [127, 133, 155, null]],
-[133, "box", 575, 636, [132, 189, null]],
+[127, ["until", 103], 498, 652, [180, 132, 451, null]],
+[128, ["storein", 20], 516, 720, [451, 186, 236, 136]],
+[129, ["string", "ii"], 638, 720, [186, null]],
+[130, "box", 638, 844, [236, 187, null]],
+[131, ["string", "ii"], 747, 844, [187, null]],
+[132, ["equal2", 20], 554, 884, [127, 133, 155, null]],
+[133, "box", 610, 884, [132, 189, null]],
[134, "hat", 360, 360, [null, 135, 215]],
[135, ["string", "draw cluster"], 418, 372, [134, null]],
-[136, ["vspace", 20], 463, 628, [180, 127]],
+[136, ["vspace", 20], 516, 844, [128, null]],
[137, "stack", 223, 1244, [407, 138, 296]],
[138, ["string", "draw cluster"], 281, 1244, [137, null]],
[139, "box", 435, 210, [142, 140, null]],
@@ -154,8 +154,8 @@
[152, ["string", "display prime factors"], 306, 658, [151, null]],
[153, ["storein", 0], 223, 700, [151, 154, 175, 100]],
[154, ["string", "level"], 291, 700, [153, null]],
-[155, "box", 575, 718, [132, 182, null]],
-[156, ["string", "ii"], 585, 504, [177, null]],
+[155, "box", 610, 966, [132, 182, null]],
+[156, ["string", "ii"], 620, 528, [177, null]],
[157, ["ifelse", [0, 0]],
583, 772, [162, 158, 443, 445, 110]],
[158, ["equal2", 0], 639, 738, [157, 163, 159, null]],
@@ -177,21 +177,21 @@
[174, ["vspace", 20], 583, 606, [104, 107]],
[175, "box", 291, 742, [153, 176, null]],
[176, ["string", "count"], 346, 742, [175, null]],
-[177, ["plus2", 0], 531, 504, [180, 156, 178]],
-[178, "box", 585, 546, [177, 179, null]],
-[179, ["string", "level"], 640, 546, [178, null]],
-[180, ["storein", 20], 463, 504, [206, 177, 181, 136]],
-[181, ["number", 0], 531, 586, [180, null]],
-[182, "box", 630, 718, [155, 183, null]],
-[183, ["string", "level"], 685, 718, [182, null]],
-[184, "box", 603, 860, [186, 185, null]],
-[185, ["string", "level"], 658, 860, [184, null]],
-[186, ["plus2", 0], 549, 818, [128, 129, 184]],
-[187, ["plus2", 0], 658, 942, [130, 131, 234]],
+[177, ["plus2", 0], 566, 528, [180, 156, 178]],
+[178, "box", 620, 570, [177, 179, null]],
+[179, ["string", "level"], 675, 570, [178, null]],
+[180, ["storein", 20], 498, 528, [206, 177, 181, 127]],
+[181, ["number", 0], 566, 610, [180, null]],
+[182, "box", 665, 966, [155, 183, null]],
+[183, ["string", "level"], 720, 966, [182, null]],
+[184, "box", 638, 762, [186, 185, null]],
+[185, ["string", "level"], 693, 762, [184, null]],
+[186, ["plus2", 0], 584, 720, [128, 129, 184]],
+[187, ["plus2", 0], 693, 844, [130, 131, 234]],
[188, "box", 789, 648, [106, 192, null]],
-[189, ["plus2", 0], 630, 636, [133, 103, 190]],
-[190, "box", 684, 678, [189, 191, null]],
-[191, ["string", "level"], 739, 678, [190, null]],
+[189, ["plus2", 0], 665, 884, [133, 103, 190]],
+[190, "box", 719, 926, [189, 191, null]],
+[191, ["string", "level"], 774, 926, [190, null]],
[192, "box", 844, 648, [188, 193, null]],
[193, ["string", "level"], 899, 648, [192, null]],
[194, ["plus2", 0], 231, 584, [204, 202, 196]],
@@ -233,10 +233,10 @@
[230, "box", 580, 346, [228, 231, null]],
[231, ["string", "factor"], 635, 346, [230, null]],
[232, ["vspace", 0], 443, 346, [227, 98]],
-[233, ["number", 1], 603, 900, [236, null]],
-[234, "box", 712, 984, [187, 235, null]],
-[235, ["string", "level"], 767, 984, [234, null]],
-[236, ["plus2", 0], 549, 900, [128, 233, 130]],
+[233, ["number", 1], 638, 802, [236, null]],
+[234, "box", 747, 886, [187, 235, null]],
+[235, ["string", "level"], 802, 886, [234, null]],
+[236, ["plus2", 0], 584, 802, [128, 233, 130]],
[237, "heading", 695, 564, [238, null]],
[238, ["plus2", 0], 641, 564, [104, 237, 106]],
[239, "hat", 180, 520, [null, 240, 254]],
@@ -274,7 +274,7 @@
[271, ["string", "action"], 298, 312, [270, null]],
[272, "stack", 219, 690, [2, 273, 461]],
[273, ["string", "action"], 277, 690, [272, null]],
-[274, "wait", 1064, 422, [479, 465, null]],
+[274, "wait", 1029, 398, [479, 465, null]],
[275, ["storein", 0], 219, 774, [461, 276, 280, null]],
[276, ["string", "number"], 287, 774, [275, null]],
[277, ["number", 1], 341, 858, [280, null]],
@@ -412,13 +412,13 @@
[407, "setgray", 223, 1202, [293, 408, 137]],
[408, ["number", 0], 296, 1202, [407, null]],
[409, "clean", 183, 170, [361, 381]],
-[410, "mousey", 1186, 298, [414, null]],
-[411, "height", 1256, 340, [412, null]],
-[412, ["division2", 0], 1186, 340, [414, 411, 413]],
-[413, ["number", 2], 1280, 382, [412, null]],
-[414, ["plus2", 0], 1132, 298, [475, 410, 412]],
-[415, ["division2", 0], 1192, 422, [465, 416, 477]],
-[416, "height", 1262, 422, [415, null]],
+[410, "mousey", 1151, 274, [414, null]],
+[411, "height", 1221, 316, [412, null]],
+[412, ["division2", 0], 1151, 316, [414, 411, 413]],
+[413, ["number", 2], 1245, 358, [412, null]],
+[414, ["plus2", 0], 1097, 274, [475, 410, 412]],
+[415, ["division2", 0], 1157, 398, [465, 416, 477]],
+[416, "height", 1227, 398, [415, null]],
[417, "toppos", 894, 428, [427, null]],
[418, "bottompos", 875, 678, [438, null]],
[419, "rightpos", 894, 346, [426, null]],
@@ -453,8 +453,8 @@
[448, "sandwichclampcollapsed", 720, 634, [439, 398, null]],
[449, "hat", 600, 500, [null, 450, 453]],
[450, ["string", "radiate"], 658, 512, [449, null]],
-[451, "stack", 481, 776, [127, 452, 128]],
-[452, ["string", "radiate"], 539, 776, [451, null]],
+[451, "stack", 516, 678, [127, 452, 128]],
+[452, ["string", "radiate"], 574, 678, [451, null]],
[453, "sandwichclampcollapsed", 600, 554, [449, 104, null]],
[454, "hat", 780, 240, [null, 455, 458]],
[455, ["string", "display scale"], 838, 252, [454, null]],
@@ -465,10 +465,10 @@
[460, ["string", "pause"], 1086, 138, [459, null]],
[461, "stack", 219, 732, [272, 462, 275]],
[462, ["string", "pause"], 277, 732, [461, null]],
-[463, ["repeat", 83], 1046, 214, [467, 464, 475, null]],
-[464, ["number", 10], 1105, 214, [463, null]],
-[465, ["division2", 20], 1122, 422, [274, 415, 466]],
-[466, ["number", 10], 1216, 504, [465, null]],
+[463, ["repeat", 83], 1011, 190, [467, 464, 475, null]],
+[464, ["number", 10], 1070, 190, [463, null]],
+[465, ["division2", 20], 1087, 398, [274, 415, 466]],
+[466, ["number", 10], 1181, 480, [465, null]],
[467, "sandwichclampcollapsed", 1028, 180, [459, 463, null]],
[468, "fullscreen", 200, 118, [0, 361]],
[469, ["product2", 20], 291, 994, [390, 252, 470]],
@@ -477,9 +477,8 @@
[472, "int", 827, 788, [321, 322]],
[473, "int", 583, 704, [334, 338]],
[474, "int", 637, 890, [337, 340]],
-[475, ["storein", 0], 1064, 256, [463, 476, 414, 479]],
-[476, ["string", "yy"], 1132, 256, [475, null]],
-[477, "box", 1286, 464, [415, 478, null]],
-[478, ["string", "yy"], 1341, 464, [477, null]],
-[479, ["vspace", 20], 1064, 340, [475, 274]],
-[-1, ["turtle", "Yertle"], 0.0, 0.0, 0.0, 0, 50, 5]] \ No newline at end of file
+[475, ["storein", 0], 1029, 232, [463, 476, 414, 479]],
+[476, ["string", "yy"], 1097, 232, [475, null]],
+[477, "box", 1251, 440, [415, 478, null]],
+[478, ["string", "yy"], 1306, 440, [477, null]],
+[479, ["vspace", 20], 1029, 316, [475, 274]]]