Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TurtleArtActivity.py20
-rwxr-xr-xsprite_factory.py9
-rw-r--r--tacanvas.py8
-rw-r--r--talogo.py12
-rw-r--r--tautils.py108
-rw-r--r--tawindow.py252
-rwxr-xr-xturtleart.py6
7 files changed, 380 insertions, 35 deletions
diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py
index 1cbe1ce..949408d 100644
--- a/TurtleArtActivity.py
+++ b/TurtleArtActivity.py
@@ -248,7 +248,7 @@ class TurtleArtActivity(activity.Activity):
# FIXME: this was like this before refactoring, the save_pict
# belongs to taproject (not tawindow)
- tawindow.save_pict(self.tw,file_path)
+ self.tw.save_pict(file_path)
# Create a datastore object
dsobject = datastore.create()
@@ -283,7 +283,7 @@ class TurtleArtActivity(activity.Activity):
print tafile
try:
# FIXME: encapsulation?
- tawindow.save_data(self.tw,tafile)
+ self.tw.save_data(tafile)
except:
_logger.debug("couldn't save snapshot to journal")
@@ -391,7 +391,7 @@ class TurtleArtActivity(activity.Activity):
""" Sample projects open dialog """
def _do_samples_cb(self, button):
# FIXME: encapsulation!
- tawindow.load_file(self.tw, True)
+ self.tw.load_file(True)
# run the activity
self.stop_button.set_icon("stopiton")
self.tw.run_button(0)
@@ -568,7 +568,7 @@ class TurtleArtActivity(activity.Activity):
# sharer should send current state to joiner
if self.initiating is True:
_logger.debug("serialize the project and send to joiner")
- text = tawindow.save_string(self.tw)
+ text = self.tw.save_string()
self._send_event("I:" + text)
self.tw.show_palette()
elif text[0] == 'I': # receiving current state
@@ -576,7 +576,7 @@ class TurtleArtActivity(activity.Activity):
_logger.debug("receiving project from sharer")
e,text = re.split(":",text,2)
# unpack data
- tawindow.load_string(self.tw,text)
+ self.tw.load_string(text)
# all caught up
self.waiting_for_blocks = False
@@ -943,6 +943,7 @@ class TurtleArtActivity(activity.Activity):
"""
def _setup_canvas(self, canvas, lang):
bundle_path = activity.get_bundle_path()
+ print "turtle colors = %s" % (profile.get_color().to_string())
self.tw = tawindow.TurtleArtWindow(canvas, bundle_path, lang, self)
self.tw.activity = self
self.tw.window.grab_focus()
@@ -952,7 +953,7 @@ class TurtleArtActivity(activity.Activity):
if self._jobject and self._jobject.file_path:
self.read_file(self._jobject.file_path)
else: # if new, load a start brick onto the canvas
- tawindow.load_start(self.tw)
+ self.tw.load_start()
"""
Check to see if there is Python code to be loaded
@@ -1011,7 +1012,7 @@ class TurtleArtActivity(activity.Activity):
def write_file(self, file_path):
_logger.debug("Write file: %s" % file_path)
self.metadata['mime_type'] = 'application/x-turtle-art'
- tawindow.save_data(self.tw,file_path)
+ self.tw.save_data(file_path)
"""
Read a project in and then run it
@@ -1030,8 +1031,7 @@ class TurtleArtActivity(activity.Activity):
# but we will ignore the .png file
# If run_it is True, we want to create a new project
tar_fd.extractall(tmpdir)
- tawindow.load_files(self.tw, \
- os.path.join(tmpdir,'ta_code.ta'), \
+ self.tw.load_files(os.path.join(tmpdir,'ta_code.ta'), \
run_it) # create a new project flag
finally:
shutil.rmtree(tmpdir)
@@ -1039,7 +1039,7 @@ class TurtleArtActivity(activity.Activity):
# Otherwise, assume it is a .ta file
else:
print "trying to open a .ta file:" + file_path
- tawindow.load_files(self.tw, file_path, run_it)
+ self.tw.load_files(file_path, run_it)
# run the activity
if run_it:
diff --git a/sprite_factory.py b/sprite_factory.py
index c3be33a..9d4056a 100755
--- a/sprite_factory.py
+++ b/sprite_factory.py
@@ -627,9 +627,12 @@ class SVG:
return self._rline_to(self._slot_x, 0)
def _do_tail(self):
- return "%s%s" % (
- self._rline_to(-self._slot_x/2.0, self._slot_y*2.0),
- self._rline_to(-self._slot_x/2.0, -self._slot_y*2.0))
+ if self._outie is True:
+ return self._rline_to(-self._slot_x, 0)
+ else:
+ return "%s%s" % (
+ self._rline_to(-self._slot_x/2.0, self._slot_y*2.0),
+ self._rline_to(-self._slot_x/2.0, -self._slot_y*2.0))
def _do_tab(self):
s = "%s%s%s%s%s" % (
diff --git a/tacanvas.py b/tacanvas.py
index 91a7b0c..bc42a63 100644
--- a/tacanvas.py
+++ b/tacanvas.py
@@ -20,10 +20,8 @@
#THE SOFTWARE.
import gtk
-from math import sin,cos,pi
-from tasetup import load_image
-import sprites
-import taturtle
+from math import sin, cos, pi
+from sprites import Sprite
import pango
from constants import *
@@ -71,7 +69,7 @@ class TurtleGraphics:
self.tw = tw
self.width = width
self.height = height
- self.canvas = sprites.Sprite(tw.sprite_list, 0, 0,
+ self.canvas = Sprite(tw.sprite_list, 0, 0,
gtk.gdk.Pixmap(self.tw.area, self.width, self.height, -1))
(self.cx, self.cy) = self.canvas.get_xy()
self.canvas.type = 'canvas'
diff --git a/talogo.py b/talogo.py
index bf2a96b..dbd84ad 100644
--- a/talogo.py
+++ b/talogo.py
@@ -150,6 +150,10 @@ def tasqrt(x):
def identity(x):
return(x)
+def start_stack(tw):
+ if tw.running_sugar():
+ tw.activity.recenter()
+
def display_coordinates(tw, a=-1, b=-1, d=-1):
if a==-1 and b==-1 and d == -1:
x = round_int(tw.canvas.xcor/tw.coord_scale)
@@ -300,7 +304,7 @@ class LogoCode:
'stack1':[0, self.prim_stack1, True],
'stack':[1, self.prim_stack, True],
'stack2':[0, self.prim_stack2, True],
- 'start':[0, lambda self: self.start_stack()],
+ 'start':[0, lambda self: start_stack(self.tw)],
'stopstack':[0, self.prim_stopstack],
'storeinbox1':[1, lambda self,x: self.setbox('box1',x)],
'storeinbox2':[1, lambda self,x: self.setbox('box2',x)],
@@ -693,13 +697,9 @@ class LogoCode:
def defprim(self, name, args, fcn, rprim=False):
sym = self.intern(name)
- sym.nargs, sym.fcn = args,fcn
+ sym.nargs, sym.fcn = args, fcn
sym.rprim = rprim
- def start_stack(self):
- if self.tw.running_sugar():
- self.tw.activity.recenter()
-
def box(self, x):
try:
return self.boxes['box3'+str(x)]
diff --git a/tautils.py b/tautils.py
new file mode 100644
index 0000000..83305a8
--- /dev/null
+++ b/tautils.py
@@ -0,0 +1,108 @@
+#Copyright (c) 2007-8, Playful Invention Company.
+#Copyright (c) 2008-10, Walter Bender
+
+#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
+import pickle
+try:
+ _old_Sugar_system = False
+ import json
+ json.dumps
+ from json import load as jload
+ from json import dump as jdump
+except (ImportError, AttributeError):
+ try:
+ import simplejson as json
+ from simplejson import load as jload
+ from simplejson import dump as jdump
+ except:
+ _old_Sugar_system = True
+
+from StringIO import StringIO
+import os.path
+
+def json_load(text):
+ if _old_Sugar_system is True:
+ listdata = json.read(text)
+ else:
+ io = StringIO(text)
+ listdata = jload(io)
+ # json converts tuples to lists, so we need to convert back,
+ return _tuplify(listdata)
+
+def _tuplify(t):
+ if type(t) is not list:
+ return t
+ return tuple(map(_tuplify, t))
+
+def get_id(c):
+ if c is None:
+ return None
+ return c.id
+
+def json_dump(data):
+ if _old_Sugar_system is True:
+ return json.write(data)
+ else:
+ io = StringIO()
+ jdump(data,io)
+ return io.getvalue()
+
+def get_load_name(suffix, load_save_folder):
+ print "get_load_name: %s %s" % (suffix, load_save_folder)
+ 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)
+
+#
+# We try to maintain read-compatibility with all versions of Turtle Art.
+# Try pickle first; then selfo different versions of json.
+#
+def data_from_file(ta_file):
+ # Just open the .ta file, ignoring any .png file that might be present.
+ f = open(ta_file, "r")
+ try:
+ data = pickle.load(f)
+ except:
+ # Rewind necessary because of failed pickle.load attempt
+ f.seek(0)
+ text = f.read()
+ data = json_load(text)
+ f.close()
+ return data
+
+def do_dialog(dialog, suffix, load_save_folder):
+ print "do_dialog: %s %s" % (suffix, load_save_folder)
+ result = None
+ filter = gtk.FileFilter()
+ filter.add_pattern('*'+suffix)
+ filter.set_name("Turtle Art")
+ dialog.add_filter(filter)
+ dialog.set_current_folder(load_save_folder)
+ 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
+
diff --git a/tawindow.py b/tawindow.py
index d0c1587..e4bce3b 100644
--- a/tawindow.py
+++ b/tawindow.py
@@ -47,7 +47,7 @@ except:
from gettext import gettext as _
from tahoverhelp import *
-from taproject import *
+from tautils import *
from sprite_factory import SVG, svg_str_to_pixbuf
from talogo import LogoCode, stop_logo, get_pixbuf_from_journal,\
display_coordinates, movie_media_type, audio_media_type
@@ -73,10 +73,8 @@ class TurtleArtWindow():
def _setup_initial_values(self, win, path, lang, parent):
self.window = win
- self.path = os.path.join(path,'images')
- self.path_lang = os.path.join(path,'images',lang)
- self.path_en = os.path.join(path,'images/en') # en as fallback
- self.load_save_folder = os.path.join(path,'samples')
+ self.path = os.path.join(path, 'images')
+ self.load_save_folder = os.path.join(path, 'samples')
self.save_folder = None
self.save_file_name = None
self.window.set_flags(gtk.CAN_FOCUS)
@@ -1070,7 +1068,8 @@ class TurtleArtWindow():
chooser.destroy()
del chooser
else:
- fname = get_load_name(self, '.*')
+ fname, self.load_save_folder = get_load_name('.*',
+ self.load_save_folder)
if fname is None:
return
if movie_media_type(fname[-4:]):
@@ -1304,7 +1303,7 @@ class TurtleArtWindow():
if self.running_sugar():
self.activity.import_py()
else:
- load_python_code(self)
+ self.load_python_code()
self.set_userdefined()
"""
@@ -1336,4 +1335,241 @@ class TurtleArtWindow():
self.selected_blk.spr.set_label(s)
self.selected_blk.values[0] = s
-
+ def new_project(self):
+ stop_logo(self)
+ for b in self._just_blocks():
+ b.spr.hide()
+ self.canvas.clearscreen()
+ self.save_file_name = None
+
+ def load_file(self, create_new_project=True):
+ fname, self.load_save_folder = get_load_name('.ta',
+ self.load_save_folder)
+ if fname==None:
+ return
+ if fname[-3:] == '.ta':
+ fname=fname[0:-3]
+ self.load_files(fname+'.ta', create_new_project)
+ if create_new_project is True:
+ self.save_file_name = os.path.basename(fname)
+
+ def load_python_code(self):
+ fname, self.load_save_folder = get_load_name('.py',
+ self.load_save_folder)
+ if fname==None:
+ return
+ f = open(fname, 'r')
+ self.myblock = f.read()
+ f.close()
+
+ def load_files(self, ta_file, create_new_project=True):
+ if create_new_project is True:
+ self.new_project()
+ self.read_data(data_from_file(ta_file))
+
+ # Unpack serialized data sent across a share.
+ def load_string(self, text):
+ data = json_load(text)
+ self.new_project()
+ self.read_data(data)
+
+ # Unpack serialized data from the clipboard.
+ def clone_stack(self, text):
+ data = json_load(text)
+ self.read_data(data)
+
+ def read_data(self, data):
+ # Create the blocks.
+ blocks = []
+ t = 0
+ for b in data:
+ if b[1] == 'turtle':
+ self.load_turtle(b)
+ t = 1
+ else:
+ blk = self.load_block(b)
+ blocks.append(blk)
+ # Make the connections.
+ for i in range(len(blocks)):
+ cons=[]
+ for c in data[i][4]:
+ if c is None:
+ cons.append(None)
+ else:
+ cons.append(blocks[c])
+ blocks[i].connections = cons
+ # Adjust the x,y positions, as block sizes may have changed.
+ for b in blocks:
+ (sx, sy) = b.spr.get_xy()
+ for i, c in enumerate(b.connections):
+ if c is not None:
+ bdock = b.docks[i]
+ if len(c.docks) != len(c.connections):
+ print "dock-conn mismatch %s %s" % (b.name, c.name)
+ else:
+ for j in range(len(c.docks)):
+ if c.connections[j] == b:
+ cdock = c.docks[j]
+ nx, ny = sx+bdock[2]-cdock[2], sy+bdock[3]-cdock[3]
+ c.spr.move((nx, ny))
+
+ def load_block(self, b):
+ # A block is saved as: (i, (btype, value), x, y, (c0,... cn))
+ # The x,y position is saved/loaded for backward compatibility
+ btype, value = b[1], None
+ if type(btype) == type((1,2)):
+ btype, value = btype
+ if btype in CONTENT_BLOCKS:
+ if btype == 'number':
+ try:
+ values = [int(value)]
+ except ValueError:
+ values = [float(value)]
+ else:
+ values = [value]
+ else:
+ values = []
+
+ if OLD_NAMES.has_key(btype):
+ btype = OLD_NAMES[btype]
+
+ blk = Block(self.block_list, self.sprite_list,
+ btype, b[2]+self.canvas.cx,
+ b[3]+self.canvas.cy, 'block', values)
+ # Some blocks get a skin.
+ if btype == 'nop':
+ if self.nop == 'pythonloaded':
+ blk.spr.set_image(self.media_shapes['pythonon'], 1, 17, 8)
+ else:
+ blk.spr.set_image(self.media_shapes['pythonoff'], 1, 17, 8)
+ blk.spr.set_label(' ')
+ elif btype in EXPANDABLE:
+ if btype == 'vspace':
+ blk.expand_in_y(value)
+ elif btype == 'hspace':
+ blk.expand_in_x(value)
+ elif btype == 'list':
+ for i in range(len(b[4])-4):
+ dy = blk.add_arg()
+ elif btype in BOX_STYLE_MEDIA and len(blk.values)>0:
+ if btype == 'audio' or btype == 'description':
+ print "restoring %s to %s block" % (blk.values[0],blk.name)
+ blk.spr.set_image(self.media_shapes[btype+'on'], 1, 37, 6)
+ elif self.running_sugar():
+ try:
+ if blk.values[0] != 'None':
+ dsobject = datastore.get(blk.values[0])
+ if not movie_media_type(dsobject.file_path[-4:]):
+ pixbuf = get_pixbuf_from_journal(dsobject, 80, 60)
+ if pixbuf is not None:
+ blk.spr.set_image(pixbuf, 1, 17, 2)
+ else:
+ blk.spr.set_image(
+ self.media_shapes['journalon'], 1, 37, 6)
+ dsobject.destroy()
+ except:
+ print "couldn't open dsobject (%s)" % (blk.values[0])
+ else:
+ if not movie_media_type(blk.values[0][-4:]):
+ pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(blk.values[0],
+ 80, 60)
+ if pixbuf is not None:
+ blk.spr.set_image(pixbuf, 1, 17, 2)
+ else:
+ blk.spr.set_image(self.media_shapes['journalon'], 1, 37, 6)
+ blk.spr.set_label(' ')
+ blk.resize()
+ elif btype in BOX_STYLE_MEDIA:
+ blk.spr.set_label(' ')
+ blk.spr.set_image(self.media_shapes[btype+'off'], 1, 37, 6)
+
+ blk.spr.set_layer(BLOCK_LAYER)
+ return blk
+
+ def load_turtle(self, b):
+ id, name, xcor, ycor, heading, color, shade, pensize = b
+ self.canvas.setxy(xcor, ycor)
+ self.canvas.seth(heading)
+ self.canvas.setcolor(color)
+ self.canvas.setshade(shade)
+ self.canvas.setpensize(pensize)
+
+ # start a new project with a start brick
+ def load_start(self):
+ self.clone_stack("%s%s%s" % ("[[0,[\"start\",\"", _("start"),
+ "\"],250,250,[null,null]]]"))
+
+ def save_file(self):
+ if self.save_folder is not None:
+ self.load_save_folder = self.save_folder
+ fname = self._get_save_name()
+ if fname is None:
+ return
+ if fname[-3:]=='.ta':
+ fname=fname[0:-3]
+ save_data(self,fname+".ta")
+ self.save_file_name = os.path.basename(fname)
+
+ def _get_save_name(self):
+ 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)
+ if self.save_file_name is not None:
+ dialog.set_current_name(self.save_file_name+'.ta')
+ result, self.load_save_folder = self.do_dialog(dialog, '.ta')
+ return result
+
+ def save_data(self, fname):
+ f = file(fname, "w")
+ data = self._assemble_data_to_save()
+ f.write(json_dump(data))
+ f.close()
+
+ # Used to send data across a shared session
+ def save_string(self, save_turtle=True):
+ data = self._assemble_data_to_save(save_turtle)
+ return json_dump(data)
+
+ def _assemble_data_to_save(self, save_turtle=True):
+ data = []
+ for i, b in enumerate(self._just_blocks()):
+ b.id = i
+ for b in self._just_blocks():
+ if b.name in CONTENT_BLOCKS:
+ name = (b.name, b.values[0])
+ elif b.name in EXPANDABLE:
+ ex, ey = b.get_expand_x_y()
+ if ex > 0:
+ name = (b.name, ex)
+ elif ey > 0:
+ name = (b.name, ey)
+ else:
+ name = (b.name, 0)
+ else:
+ name = (b.name)
+ if hasattr(b, 'connections'):
+ connections = [get_id(c) for c in b.connections]
+ else:
+ connections = None
+ (sx, sy) = b.spr.get_xy()
+ data.append((b.id, name, sx-self.canvas.cx, sy-self.canvas.cy,
+ connections))
+ if save_turtle is True:
+ data.append((-1,'turtle',
+ self.canvas.xcor, self.canvas.ycor, self.canvas.heading,
+ self.canvas.color, self.canvas.shade,
+ self.canvas.pensize))
+ return data
+
+ # Serialize a stack to save to the clipboard
+ # TODO: check to make sure just the stack and not the project is saved
+ def serialize_stack(self):
+ data = self._assemble_data_to_save(False)
+ if data == []:
+ return None
+ return json_dump(data)
+
diff --git a/turtleart.py b/turtleart.py
index f1a3218..0b30929 100755
--- a/turtleart.py
+++ b/turtleart.py
@@ -144,10 +144,10 @@ class TurtleMain():
self.tw.win = win
def _do_open_cb(self, widget):
- load_file(self.tw, True)
+ self.tw.load_file(True)
def _do_save_cb(self, widget):
- save_file(self.tw)
+ self.tw.save_file()
def _do_palette_cb(self, widget):
self.tw.show_toolbar_palette(self.i)
@@ -177,7 +177,7 @@ class TurtleMain():
def _do_stop_cb(self, widget):
self.tw.lc.trace = 0
- stop_button(self.tw)
+ self.stop_button()
return