From cfddb51aa207270384ce50cd5c7508be10457e48 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Sun, 14 Mar 2010 17:41:20 +0000 Subject: new sharing logic --- diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py index 93a367a..cae2498 100644 --- a/TurtleArtActivity.py +++ b/TurtleArtActivity.py @@ -56,6 +56,7 @@ from taexporthtml import save_html from taexportlogo import save_logo from tautils import data_to_file, data_to_string, data_from_string, get_path from tawindow import TurtleArtWindow +from taturtle import Turtle SERVICE = 'org.laptop.TurtleArtActivity' IFACE = SERVICE @@ -460,7 +461,7 @@ class TurtleArtActivity(activity.Activity): f.write(code) f.close() except Exception, e: - print("Couldn't dump code to view source: " + str(e)) + _logger.error("Couldn't dump code to view source: " + str(e)) return tafile # Sharing-related callbacks @@ -473,7 +474,9 @@ class TurtleArtActivity(activity.Activity): return self.initiating = True - self.waiting_for_blocks = False + self.waiting_for_turtles = False + self.turtle_dictionary = \ + {profile.get_nick_name():profile.get_color().to_string()} _logger.debug('I am sharing...') self.conn = self._shared_activity.telepathy_conn @@ -496,8 +499,6 @@ class TurtleArtActivity(activity.Activity): 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 @@ -511,8 +512,8 @@ class TurtleArtActivity(activity.Activity): 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 + # Joiner should request current state from sharer. + self.waiting_for_turtles = True def _list_tubes_reply_cb(self, tubes): for tube_info in tubes: @@ -536,75 +537,137 @@ class TurtleArtActivity(activity.Activity): 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 + # 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: - self.send_event("i") + # Now that we have the tube, we can ask for the turtle dictionary. + if self.waiting_for_turtles: + _logger.debug("Sending a request for the turtle dictionary") + # we need to send our own nick and colors + colors = profile.get_color().to_string() + _logger.debug("t|"+data_to_string([self.tw.nick,colors])) + self.send_event("t|%s" % \ + (data_to_string([self.tw.nick,colors]))) def event_received_cb(self, text): """ Handle the receiving of events in share """ + _logger.debug(text) - """ DEPRECIATED - Events are sent as a tuple - cmd:data - where cmd is a mouse or keyboard event and data are x,y coordinates - or a keysroke """ - # 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 = text.split(":") - # _logger.debug("receiving button press: "+x+" "+y+" "+mask) - if mask == 'T': - self.tw.button_press(True, int(x), int(y), False) - else: - self.tw.button_press(False, int(x), int(y), False) - elif text[0] == 'r': # block release - e, x, y = text.split(":") - # _logger.debug("receiving button release: " + x + " " + y) - self.tw.button_release(int(x), int(y), False) - elif text[0] == 'm': # mouse move - e, x, y = text.split(":") - _logger.debug("receiving move: " + x + " " + y) - self.tw.mouse_move(0, 0, False, int(x), int(y)) - elif text[0] == 'k': # typing - e, mask, keyname = text.split(":", 3) - # _logger.debug("recieving key press: " + mask + " " + keyname) - if mask == 'T': - self.tw.key_press(True, keyname, False) - else: - self.tw.key_press(False, keyname, False) - elif text[0] == 'i': # request for current state - # sharer should send current state to joiner + Events are sent as a tuple, nick|cmd, where nick is a turle name + and cmd is a turtle event. Everyone gets the turtle dictionary from + the sharer and watches for 't' events, which indicate that a new + turtle has joined. + + """ + # Save active Turtle + save_active_turtle = self.tw.active_turtle + if text[0] == 't': # request for turtle dictionary + e = text.split("|", 2) + text = e[1] + if text > 0: + [nick, colors] = data_from_string(text) + if nick != self.tw.nick: + # There may not be a turtle dictionary. + if hasattr(self, "turtle_dictionary"): + self.turtle_dictionary[nick] = colors + else: + self.turtle_dictionary = {nick:colors} + # Add new turtle for the joiner. + self.tw.canvas.set_turtle(nick, colors) + # Sharer should send turtle dictionary. if self.initiating: - _logger.debug("serialize the project and send to joiner") - text = data_to_string(self.tw.assemble_data_to_save(True, True)) - self.send_event("I:" + text) - self.tw.show_palette() - elif text[0] == 'I': # receiving current state - if self.waiting_for_blocks: - _logger.debug("receiving project from sharer") - e, text = text.split(":", 2) + text = data_to_string(self.turtle_dictionary) + self.send_event("T|" + text) + elif text[0] == 'T': # Receiving the turtle dictionary. + if self.waiting_for_turtles: + e = text.split("|", 2) + text = e[1] if len(text) > 0: - self.tw.new_project() - self.tw.process_data(data_from_string(text)) - # all caught up - self.waiting_for_blocks = False + self.turtle_dictionary = data_from_string(text) + for nick in self.turtle_dictionary: + if nick != self.tw.nick: + colors = self.turtle_dictionary[nick] + # add new turtle for the joiner + self.tw.canvas.set_turtle(nick, colors) + self.waiting_for_turtles = False + elif text[0] == 'f': # move a turtle forward + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, x] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.forward(x, False) + elif text[0] == 'a': # move a turtle in an arc + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, [a, r]] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.arc(a, r, False) + elif text[0] == 'r': # rotate turtle + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, h] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.seth(h, False) + elif text[0] == 'x': # set turtle xy position + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, [x, y]] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.setxy(x, y, False) + elif text[0] == 'c': # set turtle pen color + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, x] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.setcolor(x, False) + elif text[0] == 's': # set turtle pen shade + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, x] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.setshade(x, False) + elif text[0] == 'w': # set turtle pen width + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, x] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.setpensize(x, False) + elif text[0] == 'p': # set turtle pen state + e = text.split("|", 2) + text = e[1] + if len(text) > 0: + [nick, x] = data_from_string(text) + if nick != self.tw.nick: + self.tw.canvas.set_turtle(nick) + self.tw.canvas.setpen(x, False) + # Restore active Turtle + self.tw.canvas.set_turtle(self.tw.turtles.get_turtle_key( + save_active_turtle)) def send_event(self, entry): """ Send event through the tube. """ - # nick = profile.get_nick_name() - # nick = nick.upper() if hasattr(self, 'chattube') and self.chattube is not None: self.chattube.SendText(entry) def __visibility_notify_cb(self, window, event): """ Callback method for when the activity's visibility changes. """ 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]: @@ -949,8 +1012,7 @@ class TurtleArtActivity(activity.Activity): if FILE.readline() == version: newversion = False except: - _logger.debug("Writing new version data...") - _logger.debug("...and creating a tamyblock.py Journal entry") + _logger.debug("Creating a tamyblock.py Journal entry") # Make sure there is a copy of tamyblock.py in the Journal if newversion: @@ -1044,7 +1106,7 @@ class TurtleArtActivity(activity.Activity): tar_fd.close() # Otherwise, assume it is a .ta file else: - print "trying to open a .ta file:" + file_path + _logger.debug("trying to open a .ta file:" + file_path) self.tw.load_files(file_path, run_it) # run the activity diff --git a/tacanvas.py b/tacanvas.py index 7398008..a6c0056 100644 --- a/tacanvas.py +++ b/tacanvas.py @@ -23,9 +23,8 @@ import gtk from math import sin, cos, pi from sprites import Sprite from tasprite_factory import SVG -from tautils import image_to_base64 +from tautils import image_to_base64, data_to_string import pango - from taconstants import CANVAS_LAYER, DEFAULT_TURTLE def wrap100(n): @@ -98,39 +97,38 @@ class TurtleGraphics: self.svg = SVG() self.svg.set_fill_color('none') self.tw.svg_string = '' - self.clearscreen() + self.clearscreen(False) - def clearscreen(self): + def clearscreen(self, share=True): rect = gtk.gdk.Rectangle(0, 0, self.width, self.height) self.gc.set_foreground(self.bgcolor) self.canvas.images[0].draw_rectangle(self.gc, True, *rect) self.invalt(0, 0, self.width, self.height) - self.setpensize(5) - self.setcolor(0) + self.setpensize(5, share) + self.setcolor(0, share) self.settextcolor(70) self.settextsize(48) - self.setshade(50) - self.pendown = True + self.setshade(50, share) + self.setpen(True, share) for turtle_key in iter(self.tw.turtles.dict): self.set_turtle(turtle_key) self.tw.active_turtle.set_color(0) self.tw.active_turtle.set_shade(50) self.tw.active_turtle.set_pen_size(5) self.tw.active_turtle.set_pen_state(True) - self.xcor, self.ycor, self.heading = 0, 0, 0 - self.move_turtle() - self.turn_turtle() + self.seth(0, share) + self.setxy(0, 0, share) self.set_turtle(DEFAULT_TURTLE) self.tw.svg_string = '' self.svg.reset_min_max() - def forward(self, n): - n *= self.tw.coord_scale + def forward(self, n, share=True): + nn = n*self.tw.coord_scale self.gc.set_foreground(self.fgcolor) oldx, oldy = self.xcor, self.ycor try: - self.xcor += n*sin(self.heading*DEGTOR) - self.ycor += n*cos(self.heading*DEGTOR) + self.xcor += nn*sin(self.heading*DEGTOR) + self.ycor += nn*cos(self.heading*DEGTOR) except: pass if self.pendown: @@ -142,14 +140,20 @@ class TurtleGraphics: self.height/2-self.ycor) self.tw.svg_string += "\"\n" self.tw.svg_string += self.svg.style() + if self.tw.sharing() and share: + self.tw.activity.send_event("f|%s" % \ + (data_to_string([self.tw.nick, int(n)]))) - def seth(self, n): + def seth(self, n, share=True): try: self.heading = n except: pass self.heading %= 360 self.turn_turtle() + if self.tw.sharing() and share: + self.tw.activity.send_event("r|%s" % \ + (data_to_string([self.tw.nick, int(self.heading)]))) def right(self, n): try: @@ -158,8 +162,11 @@ class TurtleGraphics: pass self.heading %= 360 self.turn_turtle() + if self.tw.sharing(): + self.tw.activity.send_event("r|%s" % \ + (data_to_string([self.tw.nick, int(self.heading)]))) - def arc(self, a, r): + def arc(self, a, r, share=True): self.gc.set_foreground(self.fgcolor) r *= self.tw.coord_scale try: @@ -171,6 +178,9 @@ class TurtleGraphics: pass self.move_turtle() self.turn_turtle() + if self.tw.sharing() and share: + self.tw.activity.send_event("a|%s" % \ + (data_to_string([self.tw.nick, [int(a),int(r)]]))) def rarc(self, a, r): if r < 0: @@ -236,7 +246,7 @@ class TurtleGraphics: self.tw.svg_string += "\"\n" self.tw.svg_string += self.svg.style() - def setxy(self, x, y): + def setxy(self, x, y, share=True): x *= self.tw.coord_scale y *= self.tw.coord_scale try: @@ -244,8 +254,11 @@ class TurtleGraphics: except: pass self.move_turtle() + if self.tw.sharing() and share: + self.tw.activity.send_event("x|%s" % \ + (data_to_string([self.tw.nick, [int(x), int(y)]]))) - def setpensize(self, ps): + def setpensize(self, ps, share=True): try: if ps < 0: ps = 0 @@ -256,8 +269,11 @@ class TurtleGraphics: self.gc.set_line_attributes(int(self.pensize*self.tw.coord_scale), gtk.gdk.LINE_SOLID, gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_MITER) self.svg.set_stroke_width(self.pensize) + if self.tw.sharing() and share: + self.tw.activity.send_event("w|%s" % \ + (data_to_string([self.tw.nick, int(ps)]))) - def setcolor(self, c): + def setcolor(self, c, share=True): try: self.color = c self.tcolor = c @@ -266,6 +282,9 @@ class TurtleGraphics: self.tw.active_turtle.set_color(c) self.set_fgcolor() self.set_textcolor() + if self.tw.sharing() and share: + self.tw.activity.send_event("c|%s" % \ + (data_to_string([self.tw.nick, int(c)]))) def settextcolor(self, c): try: @@ -280,7 +299,7 @@ class TurtleGraphics: except: pass - def setshade(self, s): + def setshade(self, s, share=True): try: self.shade = s except: @@ -288,16 +307,21 @@ class TurtleGraphics: self.tw.active_turtle.set_shade(s) self.set_fgcolor() self.set_textcolor() + if self.tw.sharing() and share: + self.tw.activity.send_event("s|%s" % \ + (data_to_string([self.tw.nick, int(s)]))) def fillscreen(self, c, s): oldc, olds = self.color, self.shade - self.setcolor(c); self.setshade(s) + self.setcolor(c, False) + self.setshade(s, False) rect = gtk.gdk.Rectangle(0, 0, self.width, self.height) self.gc.set_foreground(self.fgcolor) self.bgrgb = self.fgrgb[:] self.canvas.images[0].draw_rectangle(self.gc, True, *rect) self.invalt(0, 0, self.width, self.height) - self.setcolor(oldc); self.setshade(olds) + self.setcolor(oldc, False) + self.setshade(olds, False) self.tw.svg_string = '' self.svg.reset_min_max() @@ -319,8 +343,11 @@ class TurtleGraphics: r, g, b = calc_shade(r, sh), calc_shade(g, sh), calc_shade(b, sh) self.tw.textcolor = self.cm.alloc_color(r, g, b) - def setpen(self, bool): + def setpen(self, bool, share=True): self.pendown = bool + if self.tw.sharing() and share: + self.tw.activity.send_event("p|%s" % \ + (data_to_string([self.tw.nick, bool]))) def draw_pixbuf(self, pixbuf, a, b, x, y, w, h, path): w *= self.tw.coord_scale @@ -390,25 +417,22 @@ class TurtleGraphics: int(h)) self.tw.area.invalidate_rect(rect, False) - def set_turtle(self, k): + def set_turtle(self, k, colors=None): if not self.tw.turtles.dict.has_key(k): # if it is a new turtle, start it in the center of the screen - self.tw.active_turtle = self.tw.turtles.get_turtle(k, True) - self.xcor = 0 - self.ycor = 0 - self.heading = 0 - self.move_turtle() - self.turn_turtle() + self.tw.active_turtle = self.tw.turtles.get_turtle(k, True, colors) + self.seth(0, False) + self.setxy(0, 0, False) self.tw.active_turtle.set_pen_state(True) self.tw.active_turtle = self.tw.turtles.get_turtle(k, False) tx, ty = self.tw.active_turtle.get_xy() self.xcor = tx + 30 - self.width/2 self.ycor = self.height/2 - ty - 30 self.heading = self.tw.active_turtle.get_heading() - self.setcolor(self.tw.active_turtle.get_color()) - self.setshade(self.tw.active_turtle.get_shade()) - self.setpensize(self.tw.active_turtle.get_pen_size()) - self.pendown = self.tw.active_turtle.get_pen_state() + self.setcolor(self.tw.active_turtle.get_color(), False) + self.setshade(self.tw.active_turtle.get_shade(), False) + self.setpensize(self.tw.active_turtle.get_pen_size(), False) + self.setpen(self.tw.active_turtle.get_pen_state(), False) def svg_close(self): if self.tw.svg_string == '': diff --git a/taturtle.py b/taturtle.py index 9c8fe26..b6fc6a9 100644 --- a/taturtle.py +++ b/taturtle.py @@ -43,14 +43,17 @@ class Turtles: self.sprite_list = sprite_list self.default_pixbufs = [] - def get_turtle(self, k, append=False): + def get_turtle(self, k, append=False, colors=None): """ Find a turtle """ if self.dict.has_key(k): return self.dict[k] elif append is False: return None else: - Turtle(self, k) + if colors == None: + Turtle(self, k) + else: + Turtle(self, k, colors.split(',')) return self.dict[k] def get_turtle_key(self, turtle): diff --git a/tawindow.py b/tawindow.py index 7d46cf1..1c02feb 100644 --- a/tawindow.py +++ b/tawindow.py @@ -84,10 +84,12 @@ class TurtleArtWindow(): parent.show_all() self.running_sugar = True self.activity = parent + self.nick = profile.get_nick_name() else: self.window.show_all() self.running_sugar = False self.activity = None + self.nick = None self._setup_events() self.keypress = "" self.keyvalue = 0 @@ -217,7 +219,7 @@ class TurtleArtWindow(): self.toolbar_shapes[_name].type = 'toolbar' self.toolbar_shapes['stopiton'].hide() - def _sharing(self): + def sharing(self): """ Is a chattube available for sharing? """ if self.running_sugar and hasattr(self.activity, 'chattube') and\ self.activity.chattube is not None: @@ -635,11 +637,6 @@ class TurtleArtWindow(): self.window.grab_focus() x, y = xy(event) self.button_press(event.get_state()>k.gdk.CONTROL_MASK, x, y) - if self._sharing(): - if event.get_state()>k.gdk.CONTROL_MASK: - self.activity.send_event("p:%d:%d:T" % (x, y)) - else: - self.activity.send_event("p:%d:%d:F" % (x, y)) return True def button_press(self, mask, x, y, verbose=False): @@ -1206,21 +1203,9 @@ class TurtleArtWindow(): """ Button release """ x, y = xy(event) self.button_release(x, y) - if self._sharing(): - self.activity.send_event("r:" + str(x) + ":" + str(y)) return True def button_release(self, x, y, verbose=False): - if self.dx != 0 or self.dy != 0: - if self._sharing(): - if verbose: - print "processing move: %d %d" % (self.dx, self.dy) - self.activity.send_event("m:%d:%d" % (self.dx, self.dy)) - self.dx = 0 - self.dy = 0 - if verbose: - print "processing remote button release: %d, %d" % (x, y) - # We may have been moving the turtle if self.selected_turtle is not None: (tx, ty) = self.selected_turtle.get_xy() @@ -1526,9 +1511,6 @@ class TurtleArtWindow(): alt_mask = False alt_flag = 'F' self._key_press(alt_mask, keyname, keyunicode) - if keyname is not None and self._sharing(): - self.activity.send_event("k:%s:%s:%s" % (alt_flag, keyname, - str(keyunicode))) return keyname def _key_press(self, alt_mask, keyname, keyunicode, verbose=False): @@ -1541,10 +1523,7 @@ class TurtleArtWindow(): # First, process Alt keys. if alt_mask and self.selected_blk is not None: - if keyname == "i" and self._sharing(): - self.activity.waiting_for_blocks = True - self.activity.send_event("i") # request sync for sharing - elif keyname == "p": + if keyname == "p": self.hideshow_button() elif keyname == 'q': exit() -- cgit v0.9.1