diff options
Diffstat (limited to 'TurtleArtActivity.py')
-rw-r--r-- | TurtleArtActivity.py | 736 |
1 files changed, 495 insertions, 241 deletions
diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py index 88dfa8b..88b9ec4 100644 --- a/TurtleArtActivity.py +++ b/TurtleArtActivity.py @@ -1,4 +1,4 @@ -#Copyright (c) 2007-8, Playful Invention Company. +#Copyright (c) 2007-9, Playful Invention Company. #Permission is hereby granted, free of charge, to any person obtaining a copy #of this software and associated documentation files (the "Software"), to deal @@ -24,52 +24,67 @@ import talogo import pygtk pygtk.require('2.0') import gtk - -from socket import * -import sys import gobject -serverHost = '192.168.1.102' -serverPort = 5647 - -def debug_init(): - s = socket(AF_INET, SOCK_STREAM) # create a TCP socket - s.connect((serverHost, serverPort)) # connect to server on the port - sys.stdout = s.makefile() - sys.stderr = sys.stdout - gobject.timeout_add(100, debug_tick) - -def debug_tick(): - sys.stdout.flush() - return True - -#debug_init() +import logging +_logger = logging.getLogger('turtleart-activity') import sugar from sugar.activity import activity from sugar.graphics.toolbutton import ToolButton from sugar.graphics.menuitem import MenuItem from sugar.datastore import datastore + +import telepathy +from dbus.service import method, signal +from dbus.gobject_service import ExportedGObject +from sugar.presence import presenceservice +from sugar.presence.tubeconn import TubeConnection + from sugar import profile from gettext import gettext as _ import locale import os.path import os +import tarfile +import sys +from taexporthtml import * +from taexportlogo import * +import re + +SERVICE = 'org.laptop.TurtleArtActivity' +IFACE = SERVICE +PATH = '/org/laptop/TurtleArtActivity' class TurtleArtActivity(activity.Activity): + def __init__(self, handle): super(TurtleArtActivity,self).__init__(handle) - self.gamename = 'turtleart' -# self.set_title("TurtleArt...") + try: + datapath = os.path.join(activity.get_activity_root(), "data") + except: + # early versions of Sugar (e.g., 656) didn't support + # get_activity_root() + datapath = \ + "/home/olpc/.sugar/default/org.laptop.TurtleArtActivity/data" toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) + + # Notify when the visibility state changes + self.add_events(gtk.gdk.VISIBILITY_NOTIFY_MASK) + self.connect("visibility-notify-event", self.__visibility_notify_cb) + + # Add additional panels self.projectToolbar = ProjectToolbar(self) toolbox.add_toolbar( _('Project'), self.projectToolbar ) + self.saveasToolbar = SaveAsToolbar(self) + toolbox.add_toolbar( _('Save as'), self.saveasToolbar ) toolbox.show() -# toolbox._activity_toolbar.keep.connect('clicked', self._keep_clicked_cb) # patch + # set the project toolbar as the initial one selected + toolbox.set_current_toolbar(1) canvas = gtk.EventBox() @@ -78,44 +93,198 @@ class TurtleArtActivity(activity.Activity): toolbox._activity_toolbar.title.select_region(0,0) tboxh = toolbox._activity_toolbar.size_request()[1] - version = os.environ['SUGAR_BUNDLE_VERSION'] + try: + version = os.environ['SUGAR_BUNDLE_VERSION'] + except: + version = " unknown" lang = locale.getdefaultlocale()[0] - if not lang: lang = 'en' + if not lang: + lang = 'en' lang = lang[0:2] - if not os.path.isdir(os.path.join(activity.get_bundle_path(),'images',lang)): + if not os.path.isdir(os.path.join(activity.get_bundle_path(), \ + 'images', lang)): lang = 'en' # test to see if lang or version has changed since last time # if so, remove any old png files as they will need to be regenerated filename = "version.dat" versiondata = [] - + newversion = True try: - FILE = open(os.path.join(activity.get_activity_root(),"data",filename),"r") + FILE = open(os.path.join(datapath, filename), "r") if FILE.readline() == lang + version: - print "the version data hasn't changed" + newversion = False else: - print "out with the old version data", - os.system("rm " + os.path.join(activity.get_activity_root(),"data",'*.png')) + _logger.debug("out with the old, in with the new") + os.system("rm " + os.path.join(datapath, '*.png')) except: - print "writing new version data" + _logger.debug("writing new version data") + _logger.debug("and creating a tamyblock.py Journal entry") + versiondata.append(lang + version) - FILE = open(os.path.join(activity.get_activity_root(),"data",filename),"w") + FILE = open(os.path.join(datapath, filename), "w") FILE.writelines(versiondata) FILE.close() - self.tw = tawindow.twNew(canvas,activity.get_bundle_path(),lang,tboxh,self) + self.tw = tawindow.twNew(canvas,activity.get_bundle_path(), \ + lang,tboxh,self) self.tw.activity = self self.tw.window.grab_focus() - self.tw.save_folder = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data') - -# toolbox._activity_toolbar._update_title_sid = True -# toolbox._activity_toolbar.title.connect('focus-out-event', self.update_title_cb, toolbox) # patch + self.tw.save_folder=os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'], \ + 'data') if self._jobject and self._jobject.file_path: self.read_file(self._jobject.file_path) + ## sharing code + # Get the Presence Service + self.pservice = presenceservice.get_instance() + self.initiating = None # sharing (True) or joining (False) + + # add my buddy object to the list + owner = self.pservice.get_owner() + self.owner = owner + self.tw.buddies.append(self.owner) + self._share = "" + + self.connect('shared', self._shared_cb) + self.connect('joined', self._joined_cb) + + def _shared_cb(self, activity): + if self._shared_activity is None: + _logger.error("Failed to share or join activity ... \ + _shared_activity is null in _shared_cb()") + return + + self.initiating = True + self.waiting_for_blocks = False + _logger.debug('I am sharing...') + + self.conn = self._shared_activity.telepathy_conn + self.tubes_chan = self._shared_activity.telepathy_tubes_chan + self.text_chan = self._shared_activity.telepathy_text_chan + + # call back for "NewTube" signal + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal \ + ('NewTube', self._new_tube_cb) + + _logger.debug('This is my activity: making a tube...') + id = self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].OfferDBusTube( + SERVICE, {}) + + def _joined_cb(self, activity): + if self._shared_activity is None: + _logger.error("Failed to share or join activity ... \ + _shared_activity is null in _shared_cb()") + return + + self.initiating = False + _logger.debug('I joined a shared activity.') + + self.conn = self._shared_activity.telepathy_conn + self.tubes_chan = self._shared_activity.telepathy_tubes_chan + self.text_chan = self._shared_activity.telepathy_text_chan + + # call back for "NewTube" signal + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].connect_to_signal( \ + 'NewTube', self._new_tube_cb) + + _logger.debug('I am joining an activity: waiting for a tube...') + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].ListTubes( + reply_handler=self._list_tubes_reply_cb, + error_handler=self._list_tubes_error_cb) + + + # joiner should request current state from sharer + self.waiting_for_blocks = True + + def _list_tubes_reply_cb(self, tubes): + for tube_info in tubes: + self._new_tube_cb(*tube_info) + + def _list_tubes_error_cb(self, e): + _logger.error('ListTubes() failed: %s', e) + + def _new_tube_cb(self, id, initiator, type, service, params, state): + _logger.debug('New tube: ID=%d initator=%d type=%d service=%s ' + 'params=%r state=%d', id, initiator, type, service, + params, state) + + if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE): + if state == telepathy.TUBE_STATE_LOCAL_PENDING: + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES].AcceptDBusTube(id) + + tube_conn = TubeConnection(self.conn, + self.tubes_chan[telepathy.CHANNEL_TYPE_TUBES], id, \ + group_iface=self.text_chan[telepathy.CHANNEL_INTERFACE_GROUP]) + + # we'll use a chat tube to send serialized stacks back and forth + self.chattube = ChatTube(tube_conn, self.initiating, \ + self.event_received_cb) + + # now that we have the tube, we can ask for an initialization + if self.waiting_for_blocks is True: + self._send_event("i") + + # handle the receiving of events + def event_received_cb(self, text): + # maybe we can use a stack to share events to new-comers? + # self._share += "text + "\n" + if text[0] == 'p': # button press + e,x,y,mask = re.split(":",text) + # _logger.debug("receiving button press: "+x+" "+y+" "+mask) + if mask == 'T': + tawindow.button_press(self.tw,True,int(x),int(y),False) + else: + tawindow.button_press(self.tw,False,int(x),int(y),False) + elif text[0] == 'r': # block release + e,x,y = re.split(":",text) + # _logger.debug("receiving button release: " + x + " " + y) + tawindow.button_release(self.tw,int(x),int(y),False) + elif text[0] == 'm': # mouse move + e,x,y = re.split(":",text) + _logger.debug("recieving move: " + x + " " + y) + tawindow.mouse_move(self.tw,0,0,False,int(x),int(y)) + elif text[0] == 'k': # typing + e,mask,keyname = re.split(":",text,3) + # _logger.debug("recieving key press: " + mask + " " + keyname) + if mask == 'T': + tawindow.key_press(self.tw,True,keyname,False) + else: + tawindow.key_press(self.tw,False,keyname,False) + elif text[0] == 'i': # request for current state + # 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) + self._send_event("I:" + text) + tawindow.show_palette(self.tw) + elif text[0] == 'I': # receiving current state + if self.waiting_for_blocks: + _logger.debug("receiving project from sharer") + e,text = re.split(":",text,2) + # unpack data + tawindow.load_string(self.tw,text) + # all caught up + self.waiting_for_blocks = False + + # send events + def _send_event(self, entry): + # nick = profile.get_nick_name() + # nick = nick.upper() + if hasattr(self, 'chattube') and self.chattube is not None: + self.chattube.SendText(entry) + + # Callback method for when the activity's visibility changes + def __visibility_notify_cb(self, window, event): + if event.state == gtk.gdk.VISIBILITY_FULLY_OBSCURED: +# _logger.debug("I am not visible so I should free the audio") + self.tw.lc.ag = None + elif event.state in \ + [gtk.gdk.VISIBILITY_UNOBSCURED, gtk.gdk.VISIBILITY_PARTIAL]: + pass + def update_title_cb(self, widget, event, toolbox): toolbox._activity_toolbar._update_title_cb() toolbox._activity_toolbar._update_title_sid = True @@ -124,19 +293,21 @@ class TurtleArtActivity(activity.Activity): self.jobject_new_patch() def write_file(self, file_path): - print "Writing file %s" % file_path + # just save .ta file + _logger.debug("Writing file %s" % file_path) self.metadata['mime_type'] = 'application/x-tar' - import tarfile,os,tempfile + import tempfile tar_fd = tarfile.open(file_path, 'w') pngfd, pngfile = tempfile.mkstemp(".png") tafd, tafile = tempfile.mkstemp(".ta") - del pngfd, tafd + del pngfd + del tafd try: tawindow.save_data(self.tw,tafile) tawindow.save_pict(self.tw,pngfile) tar_fd.add(tafile, "ta_code.ta") - tar_fd.add(pngfile, "ta_image.png") + tar_fd.add(pngfile, "ta_image.png") finally: tar_fd.close() @@ -144,27 +315,34 @@ class TurtleArtActivity(activity.Activity): os.remove(tafile) def read_file(self, file_path): - # Better be a tar file. import tarfile,os,tempfile,shutil - print "Reading file %s" % file_path - tar_fd = tarfile.open(file_path, 'r') - tmpdir = tempfile.mkdtemp() - - try: - # We'll get 'ta_code.ta' and 'ta_image.png' - tar_fd.extractall(tmpdir) - tawindow.load_files(self.tw, os.path.join(tmpdir, 'ta_code.ta'), os.path.join(tmpdir, 'ta_image.png')) - - finally: - shutil.rmtree(tmpdir) - tar_fd.close() + _logger.debug("Reading file %s" % file_path) + # should be a tar file + if file_path[-5:] == ".gtar": + tar_fd = tarfile.open(file_path, 'r') + tmpdir = tempfile.mkdtemp() + try: + # We'll get 'ta_code.ta' and possibly a 'ta_image.png' + tar_fd.extractall(tmpdir) + tawindow.load_files(self.tw, os.path.join(tmpdir, \ + 'ta_code.ta'), os.path.join(tmpdir, 'ta_image.png')) + finally: + shutil.rmtree(tmpdir) + tar_fd.close() + # try to open a .ta file + elif file_path[-3:] == ".ta": + tawindow.load_files(self.tw, file_path, "") + + # run the activity + tawindow.runbutton(self.tw, 0) def jobject_new_patch(self): oldj = self._jobject self._jobject = datastore.create() self._jobject.metadata['title'] = oldj.metadata['title'] - self._jobject.metadata['title_set_by_user'] = oldj.metadata['title_set_by_user'] + self._jobject.metadata['title_set_by_user'] = \ + oldj.metadata['title_set_by_user'] self._jobject.metadata['activity'] = self.get_service_name() self._jobject.metadata['activity_id'] = self.get_id() self._jobject.metadata['keep'] = '0' @@ -175,44 +353,121 @@ class TurtleArtActivity(activity.Activity): datastore.write(self._jobject, reply_handler=self._internal_jobject_create_cb, error_handler=self._internal_jobject_error_cb) + self._jobject.destroy() def clear_journal(self): - jobjects, total_count = datastore.find({'activity': 'org.laptop.TurtleArtActivity'}) - print 'found', total_count, 'entries' + jobjects, total_count = datastore.find( \ + {'activity': 'org.sugarlab.TAPortfolioActivity'}) + _logger.debug('found', total_count, 'entries') for jobject in jobjects[:-1]: - print jobject.object_id + _logger.debug(jobject.object_id) datastore.delete(jobject.object_id) -class ProjectToolbar(gtk.Toolbar): +class ChatTube(ExportedGObject): + + def __init__(self, tube, is_initiator, stack_received_cb): + super(ChatTube, self).__init__(tube, PATH) + self.tube = tube + self.is_initiator = is_initiator # Are we sharing or joining activity? + self.stack_received_cb = stack_received_cb + self.stack = '' + + self.tube.add_signal_receiver(self.send_stack_cb, 'SendText', IFACE, \ + path=PATH, sender_keyword='sender') + def send_stack_cb(self, text, sender=None): + if sender == self.tube.get_unique_name(): + return + self.stack = text + self.stack_received_cb(text) + + @signal(dbus_interface=IFACE, signature='s') + def SendText(self, text): + self.stack = text + +class SaveAsToolbar(gtk.Toolbar): def __init__(self, pc): gtk.Toolbar.__init__(self) self.activity = pc - self.sampb = ToolButton( "stock-open" ) - self.sampb.set_tooltip(_('Samples')) - self.sampb.props.sensitive = True - self.sampb.connect('clicked', self.do_samples) - self.insert(self.sampb, -1) - self.sampb.show() - - # UCB Logo save source button - self.savelogo = ToolButton( "UCB-save" ) - self.savelogo.set_tooltip(_('UCB Logo')) + # HTML save source button + self.savehtml = ToolButton( "htmloff" ) + self.savehtml.set_tooltip(_('save as HTML')) + self.savehtml.props.sensitive = True + self.savehtml.connect('clicked', self.do_savehtml) + self.insert(self.savehtml, -1) + self.savehtml.show() + + # Berkeley Logo save source button + self.savelogo = ToolButton( "logo-saveoff" ) + self.savelogo.set_tooltip(_('save Logo')) self.savelogo.props.sensitive = True self.savelogo.connect('clicked', self.do_savelogo) self.insert(self.savelogo, -1) self.savelogo.show() - def do_samples(self, button): - tawindow.load_file(self.activity.tw) -# self.activity.jobject_new_patch() + def do_savehtml(self, button): + # write html out to datastore + self.savehtml.set_icon("htmlon") + _logger.debug("saving html code") + # til we add the option + embed_flag = True + + # grab code from stacks + html = save_html(self,self.activity.tw,embed_flag) + if len(html) == 0: + return + + # save the html code to the instance directory + try: + datapath = os.path.join(activity.get_activity_root(), "instance") + except: + # early versions of Sugar (656) didn't support get_activity_root() + datapath = \ + "/home/olpc/.sugar/default/org.laptop.TurtleArtActivity/instance" + + html_file = os.path.join(datapath, "taportfolio.html") + f = file(html_file, "w") + f.write(html) + f.close() + + if embed_flag == False: + # need to make a tarball that includes the images + tar_path = os.path.join(datapath, 'portfolio.tar') + tar_fd = tarfile.open(tar_path, 'w') + try: + tar_fd.add(html_file, "portfolio.html") + import glob + image_list = glob.glob(os.path.join(datapath, 'image*')) + for i in image_list: + tar_fd.add(i, os.path.basename(i)) + finally: + tar_fd.close() + + # Create a datastore object + file_dsobject = datastore.create() + + # Write any metadata (here we specifically set the title of the file + # and specify that this is a plain text file). + file_dsobject.metadata['title'] = "TAportfolio" + file_dsobject.metadata['icon-color'] = profile.get_color().to_string() + if embed_flag == True: + file_dsobject.metadata['mime_type'] = 'text/html' + file_dsobject.set_file_path(html_file) + else: + file_dsobject.metadata['mime_type'] = 'application/x-tar' + file_dsobject.set_file_path(tar_path) + + datastore.write(file_dsobject) + file_dsobject.destroy() + gobject.timeout_add(250,self.savehtml.set_icon, "htmloff") + return def do_savelogo(self, button): # write logo code out to datastore - print "saving logo code" + self.savelogo.set_icon("logo-saveon") # grab code from stacks - logocode = self.save_logo(self.activity.tw) + logocode = save_logo(self,self.activity.tw) if len(logocode) == 0: return filename = "logosession.lg" @@ -220,14 +475,22 @@ class ProjectToolbar(gtk.Toolbar): # Create a datastore object file_dsobject = datastore.create() - # Write any metadata (here we specifically set the title of the file and - # specify that this is a plain text file). + # Write any metadata (here we specifically set the title of the file + # and specify that this is a plain text file). file_dsobject.metadata['title'] = filename file_dsobject.metadata['mime_type'] = 'text/plain' file_dsobject.metadata['icon-color'] = profile.get_color().to_string() + # save the html code to the instance directory + try: + datapath = os.path.join(activity.get_activity_root(), "instance") + except: + # early versions of Sugar (656) didn't support get_activity_root() + datapath = \ + "/home/olpc/.sugar/default/org.laptop.TurtleArtActivity/instance" + #Write the actual file to the data directory of this activity's root. - file_path = os.path.join(self.activity.get_activity_root(), 'instance', filename) + file_path = os.path.join(datapath, filename) f = open(file_path, 'w') try: f.write(logocode) @@ -238,171 +501,162 @@ class ProjectToolbar(gtk.Toolbar): file_dsobject.set_file_path(file_path) datastore.write(file_dsobject) + gobject.timeout_add(250,self.savelogo.set_icon, "logo-saveoff") return - def save_logo(self, tw): - color_processing = "\ -to tasetpalette :i :r :g :b :myshade \r\ -make \"s ((:myshade - 50) / 50) \r\ -ifelse lessp :s 0 [ \r\ -make \"s (1 + (:s *0.8)) \r\ -make \"r (:r * :s) \r\ -make \"g (:g * :s) \r\ -make \"b (:b * :s) \r\ -] [ \ -make \"s (:s * 0.9) \r\ -make \"r (:r + ((100-:r) * :s)) \r\ -make \"g (:g + ((100-:g) * :s)) \r\ -make \"b (:b + ((100-:b) * :s)) \r\ -] \ -setpalette :i (list :r :g :b) \r\ -end \r\ -\ -to rgb :myi :mycolors :myshade \r\ -make \"myr first :mycolors \r\ -make \"mycolors butfirst :mycolors \r\ -make \"myg first :mycolors \r\ -make \"mycolors butfirst :mycolors \r\ -make \"myb first :mycolors \r\ -make \"mycolors butfirst :mycolors \r\ -tasetpalette :myi :myr :myg :myb :myshade \r\ -output :mycolors \r\ -end \r\ -\ -to processcolor :mycolors :myshade \r\ -if emptyp :mycolors [stop] \r\ -make \"i :i + 1 \r\ -processcolor (rgb :i :mycolors :myshade) :myshade \r\ -end \r\ -\ -to tasetshade :shade \r\ -make \"myshade modulo :shade 200 \r\ -if greaterp :myshade 99 [make \"myshade (199-:myshade)] \r\ -make \"i 7 \r\ -make \"mycolors :colors \r\ -processcolor :mycolors :myshade \r\ -end \r\ -\ -to tasetpencolor :c \r\ -make \"color (modulo (round :c) 100) \r\ -setpencolor :color + 8 \r\ -end \r\ -\ -make \"colors [ \ -100 0 0 100 5 0 100 10 0 100 15 0 100 20 0 100 25 0 100 30 0 100 35 0 100 40 0 100 45 0 \ -100 50 0 100 55 0 100 60 0 100 65 0 100 70 0 100 75 0 100 80 0 100 85 0 100 90 0 100 95 0 \ -100 100 0 90 100 0 80 100 0 70 100 0 60 100 0 50 100 0 40 100 0 30 100 0 20 100 0 10 100 0 \ -0 100 0 0 100 5 0 100 10 0 100 15 0 100 20 0 100 25 0 100 30 0 100 35 0 100 40 0 100 45 \ -0 100 50 0 100 55 0 100 60 0 100 65 0 100 70 0 100 75 0 100 80 0 100 85 0 100 90 0 100 95 \ -0 100 100 0 95 100 0 90 100 0 85 100 0 80 100 0 75 100 0 70 100 0 65 100 0 60 100 0 55 100 \ -0 50 100 0 45 100 0 40 100 0 35 100 0 30 100 0 25 100 0 20 100 0 15 100 0 10 100 0 5 100 \ -0 0 100 5 0 100 10 0 100 15 0 100 20 0 100 25 0 100 30 0 100 35 0 100 40 0 100 45 0 100 \ -50 0 100 55 0 100 60 0 100 65 0 100 70 0 100 75 0 100 80 0 100 85 0 100 90 0 100 95 0 100 \ -100 0 100 100 0 90 100 0 80 100 0 70 100 0 60 100 0 50 100 0 40 100 0 30 100 0 20 100 0 10] \r\ -make \"shade 50 \r\ -tasetshade :shade \r" - - bs = tawindow.blocks(tw) - code = "" - random = 0 - fillscreen = 0 - setcolor = 0 - setxy = 0 - pensize = 0 - tastack = 0 - arc = 0 - for b in bs: - this_stack = "" - data = self.walk_stack(tw, b) - # need to catch several special cases: - # stacks, random, setshade, et al. - stack = 0 - for d in data: - if type(d) is float: - this_stack += str(d) - else: - # transalate some TA terms into UCB Logo - if d == "storeinbox1": - this_stack += "make \"box1" - elif d == "box1": - this_stack += ":box1" - elif d == "storeinbox2": - this_stack += "make \"box2" - elif d == "box2": - this_stack += ":box2" - elif d == "shade": - this_stack += ":shade" - elif d == "setshade": - setcolor = 1 - this_stack += "tasetshade" - elif d == "color": - this_stack += "pencolor" - elif d == "nop": - this_stack += " " - elif d == "nop1": - this_stack += "to stack1\r" - stack = 1 - elif d == "nop2": - this_stack += "to stack2\r" - stack = 1 - elif d == "clean": - this_stack += "clearscreen" - elif d == "setxy": - setxy = 1 - this_stack += "tasetxy" - elif d == "color": - this_stack += ":color" - elif d == "setcolor": - setcolor = 1 - this_stack += "tasetpencolor" - elif d == "fillscreen": - fillscreen = 1 - this_stack += "tasetbackground" - elif d == "random": - random = 1 - this_stack += "tarandom" - elif d == "pensize": - pensize = 1 - this_stack += "tapensize" - elif d == "arc": - arc = 1 - this_stack += "taarc" - else: - this_stack += d - this_stack += " " - if stack: - stack = 0 - # if it is not a stack, we need to add a "to ta#" label - elif len(data) > 0: - this_stack = "to ta" + str(tastack) + "\r" + this_stack - tastack += 1 - if len(data) > 0: - code += this_stack - code += "\rend\r" - # need to define some procedures - if random: # to avoid negative numbers - code = "to tarandom :min :max\routput (random (:max - :min)) + :min\rend\r" + code - if fillscreen: # set shade than background color - code = "to tasetbackground :color :shade\rtasetshade :shade\rsetbackground :color\rend\r" + code - if setcolor: # load palette - code = color_processing + code - if pensize: # return only first argument - code = "to tapensize\routput first round pensize\rend\r" + code - if setxy: # swap args and round args - code = "to tasetxy :y :x\rpenup\rsetxy :x :y\rpendown\rend\r" + code - if arc: - c = (2 * math.pi)/360 - code = "to taarc :a :r\rrepeat round :a [right 1 forward (" + str(c) + " * :r)]\rend\r" + code - code = "window\rsetscrunch 2 2\r" + code - print code - return code - - def walk_stack(self, tw, spr): - top = tawindow.find_top_block(spr) - if spr == top: - # only walk the stack if the block is the top block - return talogo.walk_blocks(tw.lc, top, tawindow.blocks(tw)) +class ProjectToolbar(gtk.Toolbar): + + def __init__(self, pc): + gtk.Toolbar.__init__(self) + self.activity = pc + + # palette button (blocks) + self.palette = ToolButton( "blocksoff" ) + self.palette.set_tooltip(_('hide palette')) + self.palette.props.sensitive = True + self.palette.connect('clicked', self.do_palette) + self.insert(self.palette, -1) + self.palette.show() + + # blocks button (hideshow) + self.blocks = ToolButton( "hideshowoff" ) + self.blocks.set_tooltip(_('hide blocks')) + self.blocks.props.sensitive = True + self.blocks.connect('clicked', self.do_hideshow) + self.insert(self.blocks, -1) + self.blocks.show() + + separator = gtk.SeparatorToolItem() + separator.set_draw(True) + self.insert(separator, -1) + separator.show() + + # run button + self.runproject = ToolButton( "run-fastoff" ) + self.runproject.set_tooltip(_('run')) + self.runproject.props.sensitive = True + self.runproject.connect('clicked', self.do_run) + self.insert(self.runproject, -1) + self.runproject.show() + + # step button + self.stepproject = ToolButton( "run-slowoff" ) + self.stepproject.set_tooltip(_('step')) + self.stepproject.props.sensitive = True + self.stepproject.connect('clicked', self.do_step) + self.insert(self.stepproject, -1) + self.stepproject.show() + + # stop button + self.stop = ToolButton( "stopitoff" ) + self.stop.set_tooltip(_('stop turtle')) + self.stop.props.sensitive = True + self.stop.connect('clicked', self.do_stop) + self.insert(self.stop, -1) + self.stop.show() + + separator = gtk.SeparatorToolItem() + separator.set_draw(True) + self.insert(separator, -1) + separator.show() + + # eraser button + self.eraser = ToolButton( "eraseron" ) + self.eraser.set_tooltip(_('clean')) + self.eraser.props.sensitive = True + self.eraser.connect('clicked', self.do_eraser) + self.insert(self.eraser, -1) + self.eraser.show() + + separator = gtk.SeparatorToolItem() + separator.set_draw(True) + self.insert(separator, -1) + separator.show() + + # project open + self.sampb = ToolButton( "stock-open" ) + self.sampb.set_tooltip(_('samples')) + self.sampb.props.sensitive = True + self.sampb.connect('clicked', self.do_samples) + self.insert(self.sampb, -1) + self.sampb.show() + + def do_palette(self, button): + if self.activity.tw.palette == True: + tawindow.hideshow_palette(self.activity.tw,False) + self.palette.set_icon("blockson") + self.palette.set_tooltip(_('show palette')) + else: + tawindow.hideshow_palette(self.activity.tw,True) + self.palette.set_icon("blocksoff") + self.palette.set_tooltip(_('hide palette')) + + def do_hidepalette(self): + # print "in do_hidepalette" + self.palette.set_icon("blockson") + self.palette.set_tooltip(_('show palette')) + + def do_showpalette(self): + # print "in do_showpalette" + self.palette.set_icon("blocksoff") + self.palette.set_tooltip(_('hide palette')) + + def do_run(self, button): + self.runproject.set_icon("run-faston") + self.stop.set_icon("stopiton") + tawindow.runbutton(self.activity.tw, 0) + gobject.timeout_add(1000,self.runproject.set_icon,"run-fastoff") + gobject.timeout_add(1000,self.stepproject.set_icon,"run-slowoff") + + def do_step(self, button): + self.stepproject.set_icon("run-slowon") + self.stop.set_icon("stopiton") + tawindow.runbutton(self.activity.tw, 3) + gobject.timeout_add(1000,self.stepproject.set_icon,"run-slowoff") + gobject.timeout_add(1000,self.runproject.set_icon,"run-fastoff") + + def do_stop(self, button): + self.stop.set_icon("stopitoff") + tawindow.stop_button(self.activity.tw) + self.stepproject.set_icon("run-slowoff") + self.runproject.set_icon("run-fastoff") + + def do_hideshow(self, button): + tawindow.hideshow_button(self.activity.tw) + if self.activity.tw.hide == True: # we just hid the blocks + self.blocks.set_icon("hideshowon") + self.blocks.set_tooltip(_('show blocks')) else: - # not top of stack, then return empty list - return [] + self.blocks.set_icon("hideshowoff") + self.blocks.set_tooltip(_('hide blocks')) + # update palette buttons too + if self.activity.tw.palette == False: + self.palette.set_icon("blockson") + self.palette.set_tooltip(_('show palette')) + else: + self.palette.set_icon("blocksoff") + self.palette.set_tooltip(_('hide palette')) + + def do_hide(self): + self.blocks.set_icon("hideshowon") + self.blocks.set_tooltip(_('show blocks')) + self.palette.set_icon("blockson") + self.palette.set_tooltip(_('show palette')) + + def do_show(self): + self.blocks.set_icon("hideshowoff") + self.blocks.set_tooltip(_('hide blocks')) + self.palette.set_icon("blocksoff") + self.palette.set_tooltip(_('hide palette')) + + def do_eraser(self, button): + self.eraser.set_icon("eraseroff") + tawindow.eraser_button(self.activity.tw) + gobject.timeout_add(250,self.eraser.set_icon,"eraseron") + + def do_samples(self, button): + tawindow.load_file(self.activity.tw) + # run the activity + tawindow.runbutton(self.activity.tw, 0) + |