Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TurtleArt/sprites.py22
-rw-r--r--TurtleArt/taturtle.py38
-rw-r--r--TurtleArt/tautils.py461
3 files changed, 268 insertions, 253 deletions
diff --git a/TurtleArt/sprites.py b/TurtleArt/sprites.py
index baae94f..a4e97e7 100644
--- a/TurtleArt/sprites.py
+++ b/TurtleArt/sprites.py
@@ -187,7 +187,8 @@ class Sprite:
self._dy.append(0)
self._dx[i] = dx
self._dy[i] = dy
- if isinstance(image, gtk.gdk.Pixbuf):
+ if isinstance(image, gtk.gdk.Pixbuf) or \
+ isinstance(image, cairo.ImageSurface):
w = image.get_width()
h = image.get_height()
else:
@@ -200,14 +201,17 @@ class Sprite:
self.rect.width = w + dx
if h + dy > self.rect.height:
self.rect.height = h + dy
- surface = cairo.ImageSurface(
- cairo.FORMAT_ARGB32, self.rect.width, self.rect.height)
- context = cairo.Context(surface)
- context = gtk.gdk.CairoContext(context)
- context.set_source_pixbuf(image, 0, 0)
- context.rectangle(0, 0, self.rect.width, self.rect.height)
- context.fill()
- self.cached_surfaces[i] = surface
+ if isinstance(image, cairo.ImageSurface):
+ self.cached_surfaces[i] = image
+ else: # Convert to Cairo surface
+ surface = cairo.ImageSurface(
+ cairo.FORMAT_ARGB32, self.rect.width, self.rect.height)
+ context = cairo.Context(surface)
+ context = gtk.gdk.CairoContext(context)
+ context.set_source_pixbuf(image, 0, 0)
+ context.rectangle(0, 0, self.rect.width, self.rect.height)
+ context.fill()
+ self.cached_surfaces[i] = surface
def move(self, pos):
''' Move to new (x, y) position '''
diff --git a/TurtleArt/taturtle.py b/TurtleArt/taturtle.py
index c7bb768..8246419 100644
--- a/TurtleArt/taturtle.py
+++ b/TurtleArt/taturtle.py
@@ -20,8 +20,10 @@
#THE SOFTWARE.
from random import uniform
-from math import sin, cos, pi
+from math import sin, cos, pi, sqrt
from gettext import gettext as _
+import gtk
+import cairo
from taconstants import TURTLE_LAYER, DEFAULT_TURTLE_COLORS
from tasprite_factory import SVG, svg_str_to_pixbuf
@@ -176,25 +178,37 @@ class Turtle:
self.shapes = generate_turtle_pixbufs(self.colors)
self.set_heading(self.heading)
- def set_shapes(self, shapes):
+ def set_shapes(self, shapes, i=0):
""" Reskin the turtle """
n = len(shapes)
- if n == SHAPES:
+ if n == 1 and i > 0: # set shape[i]
+ if i < len(self.shapes):
+ self.shapes[i] = shapes[0]
+ elif n == SHAPES: # all shapes have been precomputed
self.shapes = shapes[:]
- else:
+ else: # rotate shapes
if n != 1:
debug_output("%d images passed to set_shapes: ignoring" % (n),
self.tw.running_sugar)
- images = [shapes[0]]
- if self.heading == 0:
- for i in range(3):
- images.append(images[i].rotate_simple(270))
+ if self.heading == 0: # rotate the shapes
+ images = []
+ w, h = shapes[0].get_width(), shapes[0].get_height()
+ w = h = int(sqrt(w * w + h * h))
for i in range(SHAPES):
- j = (i + 4) % SHAPES
- self.shapes[j] = images[int(j / 9)]
- else:
+ surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h)
+ context = cairo.Context(surface)
+ context = gtk.gdk.CairoContext(context)
+ context.translate(w / 2., h / 2.)
+ context.rotate(i * 10 * pi / 180.)
+ context.translate(-w / 2., -h / 2.)
+ context.set_source_pixbuf(shapes[0], 0, 0)
+ context.rectangle(0, 0, w, h)
+ context.fill()
+ images.append(surface)
+ self.shapes = images[:]
+ else: # associate shape with image at current heading
j = int(self.heading + 5) % 360 / (360 / SHAPES)
- self.shapes[j] = images[0]
+ self.shapes[j] = shapes[0]
self.custom_shapes = True
self.show()
diff --git a/TurtleArt/tautils.py b/TurtleArt/tautils.py
index a402563..24e89ee 100644
--- a/TurtleArt/tautils.py
+++ b/TurtleArt/tautils.py
@@ -44,12 +44,15 @@ from StringIO import StringIO
from taconstants import COLLAPSIBLE, HIT_HIDE, HIT_SHOW, XO1, XO15, XO175, \
UNKNOWN
+SANDWICHES = ['sandwichtop', 'sandwichtop_no_label', 'sandwichtop_no_arm',
+ 'sandwichtop_no_arm_no_label']
+
import logging
_logger = logging.getLogger('turtleart-activity')
def debug_output(message_string, running_sugar=False):
- """ unified debugging output """
+ ''' unified debugging output '''
if running_sugar:
_logger.debug(message_string)
else:
@@ -57,7 +60,7 @@ def debug_output(message_string, running_sugar=False):
def error_output(message_string, running_sugar=False):
- """ unified debugging output """
+ ''' unified debugging output '''
if running_sugar:
_logger.error(message_string)
else:
@@ -92,7 +95,7 @@ def convert(x, fn, try_ord=True):
def chr_to_ord(x):
- """ Try to comvert a string to an ord """
+ ''' Try to comvert a string to an ord '''
if strtype(x) and len(x) == 1:
try:
return ord(x[0]), True
@@ -102,7 +105,7 @@ def chr_to_ord(x):
def strtype(x):
- """ Is x a string type? """
+ ''' Is x a string type? '''
if type(x) == str:
return True
if type(x) == unicode:
@@ -111,15 +114,15 @@ def strtype(x):
def magnitude(pos):
- """ Calculate the magnitude of the distance between to blocks. """
+ ''' Calculate the magnitude of the distance between to blocks. '''
x, y = pos
return x * x + y * y
def json_load(text):
- """ Load JSON data using what ever resources are available. """
+ ''' Load JSON data using what ever resources are available. '''
if OLD_SUGAR_SYSTEM is True:
- _listdata = json.read(text)
+ listdata = json.read(text)
else:
# Strip out leading and trailing whitespace, nulls, and newlines
clean_text = text.lstrip()
@@ -132,137 +135,139 @@ def json_load(text):
while left_count > right_count:
clean_text += ']'
right_count = clean_text.count(']')
- _io = StringIO(clean_text)
+ io = StringIO(clean_text)
try:
- _listdata = jload(_io)
+ listdata = jload(io)
except ValueError:
# Assume that text is ascii list
- _listdata = text.split()
- for i, value in enumerate(_listdata):
- _listdata[i] = convert(value, float)
+ listdata = text.split()
+ for i, value in enumerate(listdata):
+ listdata[i] = convert(value, float)
# json converts tuples to lists, so we need to convert back,
- return _tuplify(_listdata)
+ return _tuplify(listdata)
def _tuplify(tup):
- """ Convert to tuples """
+ ''' Convert to tuples '''
if type(tup) is not list:
return tup
return tuple(map(_tuplify, tup))
def get_id(connection):
- """ Get a connection block ID. """
+ ''' Get a connection block ID. '''
if connection is not None and hasattr(connection, 'id'):
return connection.id
return None
def json_dump(data):
- """ Save data using available JSON tools. """
+ ''' Save data using available JSON tools. '''
if OLD_SUGAR_SYSTEM is True:
return json.write(data)
else:
- _io = StringIO()
- jdump(data, _io)
- return _io.getvalue()
+ io = StringIO()
+ jdump(data, io)
+ return io.getvalue()
def get_load_name(suffix, load_save_folder):
- """ Open a load file dialog. """
- _dialog = gtk.FileChooserDialog(_('Load...'), None,
+ ''' Open a load file dialog. '''
+ dialog = gtk.FileChooserDialog(
+ _('Load...'), None,
gtk.FILE_CHOOSER_ACTION_OPEN, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN, gtk.RESPONSE_OK))
- _dialog.set_default_response(gtk.RESPONSE_OK)
- return do_dialog(_dialog, suffix, load_save_folder)
+ dialog.set_default_response(gtk.RESPONSE_OK)
+ return do_dialog(dialog, suffix, load_save_folder)
def get_save_name(suffix, load_save_folder, save_file_name):
- """ Open a save file dialog. """
- _dialog = gtk.FileChooserDialog(_('Save...'), None,
+ ''' Open a save file dialog. '''
+ dialog = gtk.FileChooserDialog(
+ _('Save...'), None,
gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
- _dialog.set_default_response(gtk.RESPONSE_OK)
+ dialog.set_default_response(gtk.RESPONSE_OK)
if save_file_name is not None:
- _dialog.set_current_name(save_file_name + suffix)
- return do_dialog(_dialog, suffix, load_save_folder)
+ dialog.set_current_name(save_file_name + suffix)
+ return do_dialog(dialog, suffix, load_save_folder)
def chooser(parent_window, filter, action):
- """ Choose an object from the datastore and take some action """
+ ''' Choose an object from the datastore and take some action '''
from sugar.graphics.objectchooser import ObjectChooser
- _chooser = None
+ chooser = None
try:
- _chooser = ObjectChooser(parent=parent_window, what_filter=filter)
+ chooser = ObjectChooser(parent=parent_window, what_filter=filter)
except TypeError:
- _chooser = ObjectChooser(None, parent_window,
+ chooser = ObjectChooser(None, parent_window,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT)
- if _chooser is not None:
+ if chooser is not None:
try:
- result = _chooser.run()
+ result = chooser.run()
if result == gtk.RESPONSE_ACCEPT:
- dsobject = _chooser.get_selected_object()
+ dsobject = chooser.get_selected_object()
action(dsobject)
dsobject.destroy()
finally:
- _chooser.destroy()
- del _chooser
+ chooser.destroy()
+ del chooser
def data_from_file(ta_file):
- """ Open the .ta file, ignoring any .png file that might be present. """
- file_handle = open(ta_file, "r")
+ ''' Open the .ta file, ignoring any .png file that might be present. '''
+ file_handle = open(ta_file, 'r')
#
# We try to maintain read-compatibility with all versions of Turtle Art.
# Try pickle first; then different versions of json.
#
try:
- _data = pickle.load(file_handle)
+ data = pickle.load(file_handle)
except:
# Rewind necessary because of failed pickle.load attempt
file_handle.seek(0)
- _text = file_handle.read()
- _data = data_from_string(_text)
+ text = file_handle.read()
+ data = data_from_string(text)
file_handle.close()
- return _data
+ return data
def data_from_string(text):
- """ JSON load data from a string. """
+ ''' JSON load data from a string. '''
return json_load(text.replace(']],\n', ']], '))
def data_to_file(data, ta_file):
- """ Write data to a file. """
- file_handle = file(ta_file, "w")
+ ''' Write data to a file. '''
+ file_handle = file(ta_file, 'w')
file_handle.write(data_to_string(data))
file_handle.close()
def data_to_string(data):
- """ JSON dump a string. """
+ ''' JSON dump a string. '''
return json_dump(data).replace(']], ', ']],\n')
def do_dialog(dialog, suffix, load_save_folder):
- """ Open a file dialog. """
- _result = None
+ ''' Open a file dialog. '''
+ result = None
file_filter = gtk.FileFilter()
file_filter.add_pattern('*' + suffix)
- file_filter.set_name("Turtle Art")
+ file_filter.set_name('Turtle Art')
dialog.add_filter(file_filter)
dialog.set_current_folder(load_save_folder)
- _response = dialog.run()
- if _response == gtk.RESPONSE_OK:
- _result = dialog.get_filename()
+ response = dialog.run()
+ if response == gtk.RESPONSE_OK:
+ result = dialog.get_filename()
load_save_folder = dialog.get_current_folder()
dialog.destroy()
- return _result, load_save_folder
+ return result, load_save_folder
def save_picture(canvas, file_name):
- """ Save the canvas to a file """
+ ''' Save the canvas to a file '''
x_surface = canvas.canvas.get_target()
img_surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
canvas.width, canvas.height)
@@ -273,6 +278,7 @@ def save_picture(canvas, file_name):
def get_canvas_data(canvas):
+ ''' Get pixel data from the turtle canvas '''
x_surface = canvas.canvas.get_target()
img_surface = cairo.ImageSurface(cairo.FORMAT_RGB24,
canvas.width, canvas.height)
@@ -282,46 +288,45 @@ def get_canvas_data(canvas):
return img_surface.get_data()
-
def save_svg(string, file_name):
- """ Write a string to a file. """
- file_handle = file(file_name, "w")
+ ''' Write a string to a file. '''
+ file_handle = file(file_name, 'w')
file_handle.write(string)
file_handle.close()
def get_pixbuf_from_journal(dsobject, w, h):
- """ Load a pixbuf from a Journal object. """
+ ''' Load a pixbuf from a Journal object. '''
try:
- _pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(dsobject.file_path,
- int(w), int(h))
+ pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(dsobject.file_path,
+ int(w), int(h))
except:
try:
- _pixbufloader = \
+ pixbufloader = \
gtk.gdk.pixbuf_loader_new_with_mime_type('image/png')
- _pixbufloader.set_size(min(300, int(w)), min(225, int(h)))
- _pixbufloader.write(dsobject.metadata['preview'])
- _pixbufloader.close()
- _pixbuf = _pixbufloader.get_pixbuf()
+ pixbufloader.set_size(min(300, int(w)), min(225, int(h)))
+ pixbufloader.write(dsobject.metadata['preview'])
+ pixbufloader.close()
+ pixbuf = pixbufloader.get_pixbuf()
except:
- _pixbuf = None
- return _pixbuf
+ pixbuf = None
+ return pixbuf
def get_path(activity, subpath):
- """ Find a Rainbow-approved place for temporary files. """
+ ''' Find a Rainbow-approved place for temporary files. '''
try:
return(os.path.join(activity.get_activity_root(), subpath))
except:
# Early versions of Sugar didn't support get_activity_root()
- return(os.path.join(os.environ['HOME'], ".sugar/default",
- "org.laptop.TurtleArtActivity", subpath))
+ return(os.path.join(os.environ['HOME'], '.sugar/default',
+ 'org.laptop.TurtleArtActivity', subpath))
def image_to_base64(image_path, tmp_path):
- """ Convert an image to base64-encoded data """
+ ''' Convert an image to base64-encoded data '''
base64 = os.path.join(tmp_path, 'base64tmp')
- cmd = "base64 <" + image_path + " >" + base64
+ cmd = 'base64 <' + image_path + ' >' + base64
subprocess.check_call(cmd, shell=True)
file_handle = open(base64, 'r')
data = file_handle.read()
@@ -330,68 +335,69 @@ def image_to_base64(image_path, tmp_path):
def base64_to_image(data, path_name):
- """ Convert base64-encoded data to an image """
+ ''' Convert base64-encoded data to an image '''
base64 = os.path.join(path_name, 'base64tmp')
file_handle = open(base64, 'w')
file_handle.write(data)
file_handle.close()
file_name = os.path.join(path_name, 'imagetmp.png')
- cmd = "base64 -d <" + base64 + ">" + file_name
+ cmd = 'base64 -d <' + base64 + '>' + file_name
subprocess.check_call(cmd, shell=True)
return file_name
def movie_media_type(name):
- """ Is it movie media? """
+ ''' Is it movie media? '''
return name.lower().endswith(('.ogv', '.vob', '.mp4', '.wmv', '.mov',
'.mpeg', '.ogg', '.webm'))
def audio_media_type(name):
- """ Is it audio media? """
+ ''' Is it audio media? '''
return name.lower().endswith(('.oga', '.m4a'))
def image_media_type(name):
- """ Is it image media? """
+ ''' Is it image media? '''
return name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.tiff',
'.tif', '.svg'))
def text_media_type(name):
- """ Is it text media? """
+ ''' Is it text media? '''
return name.lower().endswith(('.txt', '.py', '.lg', '.rtf'))
def round_int(num):
- """ Remove trailing decimal places if number is an int """
+ ''' Remove trailing decimal places if number is an int '''
try:
float(num)
except TypeError:
- raise pythonerror("#syntaxerror")
+ raise pythonerror('#syntaxerror')
if int(float(num)) == num:
return int(num)
else:
if float(num) < 0:
- _nn = int((float(num) - 0.005) * 100) / 100.
+ nn = int((float(num) - 0.005) * 100) / 100.
else:
- _nn = int((float(num) + 0.005) * 100) / 100.
- if int(float(_nn)) == _nn:
- return int(_nn)
- return _nn
+ nn = int((float(num) + 0.005) * 100) / 100.
+ if int(float(nn)) == nn:
+ return int(nn)
+ return nn
def calc_image_size(spr):
- """ Calculate the maximum size for placing an image onto a sprite. """
+ ''' Calculate the maximum size for placing an image onto a sprite. '''
return int(max(spr.label_safe_width(), 1)), \
int(max(spr.label_safe_height(), 1))
+
# Collapsible stacks live between 'sandwichtop' and 'sandwichbottom' blocks
def reset_stack_arm(top):
- """ When we undock, retract the 'arm' that extends from 'sandwichtop'. """
+ ''' When we undock, retract the 'arm' that extends from 'sandwichtop'. '''
if top is not None and top.name in ['sandwichtop', 'sandwichtop_no_label']:
if top.ey > 0:
top.reset_y()
@@ -400,109 +406,103 @@ def reset_stack_arm(top):
def grow_stack_arm(top):
- """ When we dock, grow an 'arm' from 'sandwichtop'. """
+ ''' When we dock, grow an 'arm' from 'sandwichtop'. '''
if top is not None and top.name in ['sandwichtop', 'sandwichtop_no_label']:
- _bot = find_sandwich_bottom(top)
- if _bot is None:
+ bot = find_sandwich_bottom(top)
+ if bot is None:
return
if top.ey > 0:
top.reset_y()
- _ty = top.spr.get_xy()[1]
- _th = top.spr.get_dimensions()[1]
- _by = _bot.spr.get_xy()[1]
- _dy = _by - (_ty + _th)
- if _dy > 0:
- top.expand_in_y(_dy / top.scale)
+ ty = top.spr.get_xy()[1]
+ th = top.spr.get_dimensions()[1]
+ by = bot.spr.get_xy()[1]
+ dy = by - (ty + th)
+ if dy > 0:
+ top.expand_in_y(dy / top.scale)
top.svg.set_hide(True)
top.refresh()
def find_sandwich_top(blk):
- """ Find the sandwich top above this block. """
+ ''' Find the sandwich top above this block. '''
# Always follow the main branch of a flow: the first connection.
- _blk = blk.connections[0]
- while _blk is not None:
- if _blk.name in COLLAPSIBLE:
+ cblk = blk.connections[0]
+ while cblk is not None:
+ if cblk.name in COLLAPSIBLE:
return None
- if _blk.name in ['repeat', 'if', 'ifelse', 'forever', 'while']:
- if blk != _blk.connections[len(_blk.connections) - 1]:
+ if cblk.name in ['repeat', 'if', 'ifelse', 'forever', 'while']:
+ if blk != cblk.connections[len(cblk.connections) - 1]:
return None
- if _blk.name in ['sandwichtop', 'sandwichtop_no_label',
- 'sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
- return _blk
- blk = _blk
- _blk = _blk.connections[0]
+ if cblk.name in SANDWICHES:
+ return cblk
+ blk = cblk
+ cblk = cblk.connections[0]
return None
def find_sandwich_bottom(blk):
- """ Find the sandwich bottom below this block. """
+ ''' Find the sandwich bottom below this block. '''
# Always follow the main branch of a flow: the last connection.
- _blk = blk.connections[len(blk.connections) - 1]
- while _blk is not None:
- if _blk.name in ['sandwichtop', 'sandwichtop_no_label',
- 'sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
+ cblk = blk.connections[len(blk.connections) - 1]
+ while cblk is not None:
+ if cblk.name in SANDWICHES:
return None
- if _blk.name in COLLAPSIBLE:
- return _blk
- _blk = _blk.connections[len(_blk.connections) - 1]
+ if cblk.name in COLLAPSIBLE:
+ return cblk
+ cblk = cblk.connections[len(cblk.connections) - 1]
return None
def find_sandwich_top_below(blk):
- """ Find the sandwich top below this block. """
- if blk.name in ['sandwichtop', 'sandwichtop_no_label',
- 'sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
+ ''' Find the sandwich top below this block. '''
+ if blk.name in SANDWICHES:
return blk
# Always follow the main branch of a flow: the last connection.
- _blk = blk.connections[len(blk.connections) - 1]
- while _blk is not None:
- if _blk.name in ['sandwichtop', 'sandwichtop_no_label',
- 'sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
- return _blk
- _blk = _blk.connections[len(_blk.connections) - 1]
+ cblk = blk.connections[len(blk.connections) - 1]
+ while cblk is not None:
+ if cblk.name in SANDWICHES:
+ return cblk
+ cblk = cblk.connections[len(cblk.connections) - 1]
return None
def restore_stack(top):
- """ Restore the blocks between the sandwich top and sandwich bottom. """
- _group = find_group(top.connections[len(top.connections) - 1])
- _hit_bottom = False
- _bot = find_sandwich_bottom(top)
- for _blk in _group:
- if not _hit_bottom and _blk == _bot:
- _hit_bottom = True
- if len(_blk.values) == 0:
- _blk.values.append(0)
+ ''' Restore the blocks between the sandwich top and sandwich bottom. '''
+ group = find_group(top.connections[len(top.connections) - 1])
+ hit_bottom = False
+ bot = find_sandwich_bottom(top)
+ for gblk in group:
+ if not hit_bottom and gblk == bot:
+ hit_bottom = True
+ if len(gblk.values) == 0:
+ gblk.values.append(0)
else:
- _blk.values[0] = 0
- _olddx = _blk.docks[1][2]
- _olddy = _blk.docks[1][3]
+ gblk.values[0] = 0
+ olddx = gblk.docks[1][2]
+ olddy = gblk.docks[1][3]
# Replace 'sandwichcollapsed' shape with 'sandwichbottom' shape
- _blk.name = 'sandwichbottom'
- _blk.spr.set_label(' ', 1)
- _blk.svg.set_show(False)
- _blk.svg.set_hide(True)
- _blk.refresh()
+ gblk.name = 'sandwichbottom'
+ gblk.spr.set_label(' ', 1)
+ gblk.svg.set_show(False)
+ gblk.svg.set_hide(True)
+ gblk.refresh()
# Redock to previous block in group
- _you = _blk.connections[0]
- (_yx, _yy) = _you.spr.get_xy()
- _yd = _you.docks[len(_you.docks) - 1]
- (_bx, _by) = _blk.spr.get_xy()
- _dx = _yx + _yd[2] - _blk.docks[0][2] - _bx
- _dy = _yy + _yd[3] - _blk.docks[0][3] - _by
- _blk.spr.move_relative((_dx, _dy))
+ you = gblk.connections[0]
+ (yx, yy) = you.spr.get_xy()
+ yd = you.docks[len(you.docks) - 1]
+ (bx, by) = gblk.spr.get_xy()
+ dx = yx + yd[2] - gblk.docks[0][2] - bx
+ dy = yy + yd[3] - gblk.docks[0][3] - by
+ gblk.spr.move_relative((dx, dy))
# Since the shapes have changed, the dock positions have too.
- _newdx = _blk.docks[1][2]
- _newdy = _blk.docks[1][3]
- _dx += _newdx - _olddx
- _dy += _newdy - _olddy
+ dx += gblk.docks[1][2] - olddx
+ dy += gblk.docks[1][3] - olddy
else:
- if not _hit_bottom:
- _blk.spr.restore()
- _blk.status = None
+ if not hit_bottom:
+ gblk.spr.restore()
+ gblk.status = None
else:
- _blk.spr.move_relative((_dx, _dy))
+ gblk.spr.move_relative((dx, dy))
# Add 'sandwichtop' arm
if top.name == 'sandwichtop_no_arm':
top.name = 'sandwichtop'
@@ -515,7 +515,7 @@ def restore_stack(top):
def uncollapse_forks(top, looping=False):
- """ From the top, find and restore any collapsible stacks on forks. """
+ ''' From the top, find and restore any collapsible stacks on forks. '''
if top == None:
return
if looping and top.name in ['sandwichtop_no_arm',
@@ -524,68 +524,66 @@ def uncollapse_forks(top, looping=False):
return
if len(top.connections) == 0:
return
- _blk = top.connections[len(top.connections) - 1]
- while _blk is not None:
- if _blk.name in COLLAPSIBLE:
+ cblk = top.connections[len(top.connections) - 1]
+ while cblk is not None:
+ if cblk.name in COLLAPSIBLE:
return
- if _blk.name in ['sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
- restore_stack(_blk)
+ if cblk.name in ['sandwichtop_no_arm', 'sandwichtop_no_arm_no_label']:
+ restore_stack(cblk)
return
# Follow a fork
- if _blk.name in ['repeat', 'if', 'ifelse', 'forever', 'while',
+ if cblk.name in ['repeat', 'if', 'ifelse', 'forever', 'while',
'until']:
top = find_sandwich_top_below(
- _blk.connections[len(_blk.connections) - 2])
+ cblk.connections[len(cblk.connections) - 2])
if top is not None:
uncollapse_forks(top, True)
- if _blk.name == 'ifelse':
+ if cblk.name == 'ifelse':
top = find_sandwich_top_below(
- _blk.connections[len(_blk.connections) - 3])
+ cblk.connections[len(cblk.connections) - 3])
if top is not None:
uncollapse_forks(top, True)
- _blk = _blk.connections[len(_blk.connections) - 1]
+ cblk = cblk.connections[len(cblk.connections) - 1]
return
def collapse_stack(top):
- """ Hide all the blocks between the sandwich top and sandwich bottom. """
+ ''' Hide all the blocks between the sandwich top and sandwich bottom. '''
# First uncollapse any nested stacks
if top == None or top.spr == None:
return
uncollapse_forks(top)
- _hit_bottom = False
- _bot = find_sandwich_bottom(top)
- _group = find_group(top.connections[len(top.connections) - 1])
- for _blk in _group:
- if not _hit_bottom and _blk == _bot:
- _hit_bottom = True
+ hit_bottom = False
+ bot = find_sandwich_bottom(top)
+ group = find_group(top.connections[len(top.connections) - 1])
+ for gblk in group:
+ if not hit_bottom and gblk == bot:
+ hit_bottom = True
# Replace 'sandwichbottom' with invisible 'sandwichcollapsed'
- if len(_blk.values) == 0:
- _blk.values.append(1)
+ if len(gblk.values) == 0:
+ gblk.values.append(1)
else:
- _blk.values[0] = 1
- _olddx = _blk.docks[1][2]
- _olddy = _blk.docks[1][3]
- _blk.name = 'sandwichcollapsed'
- _blk.resize()
- _you = find_sandwich_top(_blk)
- (_yx, _yy) = _you.spr.get_xy()
- _yd = _you.docks[len(_you.docks) - 1]
- (_bx, _by) = _blk.spr.get_xy()
- _dx = _yx + _yd[2] - _blk.docks[0][2] - _bx
- _dy = _yy + _yd[3] - _blk.docks[0][3] - _by
- _blk.spr.move_relative((_dx, _dy))
+ gblk.values[0] = 1
+ olddx = gblk.docks[1][2]
+ olddy = gblk.docks[1][3]
+ gblk.name = 'sandwichcollapsed'
+ gblk.resize()
+ you = find_sandwich_top(gblk)
+ (yx, yy) = you.spr.get_xy()
+ yd = you.docks[len(you.docks) - 1]
+ (bx, by) = gblk.spr.get_xy()
+ dx = yx + yd[2] - gblk.docks[0][2] - bx
+ dy = yy + yd[3] - gblk.docks[0][3] - by
+ gblk.spr.move_relative((dx, dy))
# Since the shapes have changed, the dock positions have too.
- _newdx = _blk.docks[1][2]
- _newdy = _blk.docks[1][3]
- _dx += _newdx - _olddx
- _dy += _newdy - _olddy
+ dx += gblk.docks[1][2] - olddx
+ dy += gblk.docks[1][3] - olddy
else:
- if not _hit_bottom:
- _blk.spr.hide()
- _blk.status = 'collapsed'
+ if not hit_bottom:
+ gblk.spr.hide()
+ gblk.status = 'collapsed'
else:
- _blk.spr.move_relative((_dx, _dy))
+ gblk.spr.move_relative((dx, dy))
# Remove 'sandwichtop' arm
if top.name == 'sandwichtop' or top.name == 'sandwichtop_no_arm':
top.name = 'sandwichtop_no_arm'
@@ -601,7 +599,7 @@ def collapse_stack(top):
def collapsed(blk):
- """ Is this stack collapsed? """
+ ''' Is this stack collapsed? '''
if blk is not None and blk.name in COLLAPSIBLE and\
len(blk.values) == 1 and blk.values[0] != 0:
return True
@@ -609,7 +607,7 @@ def collapsed(blk):
def collapsible(blk):
- """ Can this stack be collapsed? """
+ ''' Can this stack be collapsed? '''
if blk is None or blk.name not in COLLAPSIBLE:
return False
if find_sandwich_top(blk) is None:
@@ -618,32 +616,32 @@ def collapsible(blk):
def hide_button_hit(spr, x, y):
- """ Did the sprite's hide (contract) button get hit? """
- _red, _green, _blue, _alpha = spr.get_pixel((x, y))
- if _red == HIT_HIDE:
+ ''' Did the sprite's hide (contract) button get hit? '''
+ red, green, blue, alpha = spr.get_pixel((x, y))
+ if red == HIT_HIDE:
return True
else:
return False
def show_button_hit(spr, x, y):
- """ Did the sprite's show (expand) button get hit? """
- _red, _green, _blue, _alpha = spr.get_pixel((x, y))
- if _green == HIT_SHOW:
+ ''' Did the sprite's show (expand) button get hit? '''
+ red, green, blue, alpha = spr.get_pixel((x, y))
+ if green == HIT_SHOW:
return True
else:
return False
def numeric_arg(value):
- """ Dock test: looking for a numeric value """
+ ''' Dock test: looking for a numeric value '''
if type(convert(value, float)) is float:
return True
return False
def zero_arg(value):
- """ Dock test: looking for a zero argument """
+ ''' Dock test: looking for a zero argument '''
if numeric_arg(value):
if convert(value, float) == 0:
return True
@@ -651,7 +649,7 @@ def zero_arg(value):
def neg_arg(value):
- """ Dock test: looking for a negative argument """
+ ''' Dock test: looking for a negative argument '''
if numeric_arg(value):
if convert(value, float) < 0:
return True
@@ -659,7 +657,7 @@ def neg_arg(value):
def journal_check(blk1, blk2, dock1, dock2):
- """ Dock blocks only if arg is Journal block """
+ ''' Dock blocks only if arg is Journal block '''
if blk1 == None or blk2 == None:
return True
if (blk1.name == 'skin' and dock1 == 1) and blk2.name != 'journal':
@@ -670,7 +668,7 @@ def journal_check(blk1, blk2, dock1, dock2):
def arithmetic_check(blk1, blk2, dock1, dock2):
- """ Dock strings only if they convert to numbers. Avoid /0 and root(-1)"""
+ ''' Dock strings only if they convert to numbers. Avoid /0 and root(-1)'''
if blk1 == None or blk2 == None:
return True
if blk1.name in ['sqrt', 'number', 'string'] and\
@@ -704,7 +702,7 @@ def arithmetic_check(blk1, blk2, dock1, dock2):
if not numeric_arg(blk2.values[0]):
return False
elif blk1.name in ['greater2', 'less2'] and blk2.name == 'string':
- # Non-numeric stings are OK if only both args are strings;
+ # Non-numeric stings are OK only if both args are strings;
# Lots of test conditions...
if dock1 == 1 and blk1.connections[2] is not None:
if blk1.connections[2].name == 'number':
@@ -745,25 +743,24 @@ def arithmetic_check(blk1, blk2, dock1, dock2):
def xy(event):
- """ Where is the mouse event? """
+ ''' Where is the mouse event? '''
return map(int, event.get_coords())
-"""
-Utilities related to finding blocks in stacks.
-"""
+
+# Utilities related to finding blocks in stacks.
def find_block_to_run(blk):
- """ Find a stack to run (any stack without a 'def action'on the top). """
- _top = find_top_block(blk)
- if blk == _top and blk.name[0:3] is not 'def':
+ ''' Find a stack to run (any stack without a 'def action'on the top). '''
+ top = find_top_block(blk)
+ if blk == top and blk.name[0:3] is not 'def':
return True
else:
return False
def find_top_block(blk):
- """ Find the top block in a stack. """
+ ''' Find the top block in a stack. '''
if blk is None:
return None
if len(blk.connections) == 0:
@@ -774,7 +771,7 @@ def find_top_block(blk):
def find_start_stack(blk):
- """ Find a stack with a 'start' block on top. """
+ ''' Find a stack with a 'start' block on top. '''
if blk is None:
return False
if find_top_block(blk).name == 'start':
@@ -784,30 +781,30 @@ def find_start_stack(blk):
def find_group(blk):
- """ Find the connected group of block in a stack. """
+ ''' Find the connected group of block in a stack. '''
if blk is None:
return []
- _group = [blk]
+ group = [blk]
if blk.connections is not None:
- for _blk2 in blk.connections[1:]:
- if _blk2 is not None:
- _group.extend(find_group(_blk2))
- return _group
+ for cblk in blk.connections[1:]:
+ if cblk is not None:
+ group.extend(find_group(cblk))
+ return group
def find_blk_below(blk, name):
- """ Find a specific block below this block. """
+ ''' Find a specific block below this block. '''
if blk == None or len(blk.connections) == 0:
return
- _group = find_group(blk)
- for _gblk in _group:
- if _gblk.name == name:
- return _gblk
+ group = find_group(blk)
+ for gblk in _group:
+ if gblk.name == name:
+ return gblk
return None
def get_hardware():
- """ Determine whether we are using XO 1.0, 1.5, or "unknown" hardware """
+ ''' Determine whether we are using XO 1.0, 1.5, or 'unknown' hardware '''
product = _get_dmi('product_name')
if product is None:
if os.path.exists('/sys/devices/platform/lis3lv02d/position'):