diff options
-rw-r--r-- | NEWS | 20 | ||||
-rw-r--r-- | TurtleArt/tabasics.py | 6 | ||||
-rw-r--r-- | TurtleArt/tacanvas.py | 3 | ||||
-rw-r--r-- | TurtleArt/tacollaboration.py | 5 | ||||
-rw-r--r-- | TurtleArt/taconstants.py | 2 | ||||
-rwxr-xr-x | TurtleArt/tasprite_factory.py | 33 | ||||
-rw-r--r-- | TurtleArt/tautils.py | 11 | ||||
-rw-r--r-- | TurtleArt/tawindow.py | 34 | ||||
-rw-r--r-- | TurtleArtActivity.py | 63 | ||||
-rw-r--r-- | activity/activity.info | 2 |
10 files changed, 121 insertions, 58 deletions
@@ -1,3 +1,23 @@ +148 + +ENHANCEMENTS: +* Pen/color palette changes: pen operations on one palette, colors + on a second palette +* Removed bug from all versions +* New snail icon +* Rabbit and snail change color to indicate run speed +* Clicking on a stack respects current run speed +* Turtle shape more directional +* New copy- and share-block behavior: + (1) Click on Copy Button (or Share-Block Button); + the cursor changes to a hand pointer; + (2) Click on any block or stack of blocks and that stack is + briefly highlighted and copied to the clipboard (or shared); + (3) The cursor is changed back to the standard cursor. + +BUG FIX: +* Catch unicode error in collaboration code + 147 ENHANCEMENTS: diff --git a/TurtleArt/tabasics.py b/TurtleArt/tabasics.py index e8d9378..0fb0996 100644 --- a/TurtleArt/tabasics.py +++ b/TurtleArt/tabasics.py @@ -659,9 +659,6 @@ operators')) 'greater?', 2, lambda self, x, y: primitive_dictionary['more'](x, y)) - if self.tw.canvas.width > 1024: - self._make_constant(palette, 'true', _('True'), 1) - primitive_dictionary['less'] = self._prim_less palette.add_block('less2', style='compare-porch-style', @@ -674,9 +671,6 @@ operators')) self.tw.lc.def_prim( 'less?', 2, lambda self, x, y: primitive_dictionary['less'](x, y)) - if self.tw.canvas.width > 1024: - self._make_constant(palette, 'false', _('False'), 0) - primitive_dictionary['equal'] = self._prim_equal palette.add_block('equal2', style='compare-style', diff --git a/TurtleArt/tacanvas.py b/TurtleArt/tacanvas.py index 5bd0326..878d40d 100644 --- a/TurtleArt/tacanvas.py +++ b/TurtleArt/tacanvas.py @@ -21,6 +21,7 @@ #THE SOFTWARE. import gtk +import gobject from math import sin, cos, atan, pi, sqrt import os import pango @@ -592,7 +593,7 @@ class TurtleGraphics: round_int(width), round_int(height), data]])) - self.tw.send_event(event) + gobject.idle_add(self.tw.send_event, event) os.remove(tmp_file) def draw_text(self, label, x, y, size, w, share=True): diff --git a/TurtleArt/tacollaboration.py b/TurtleArt/tacollaboration.py index d4798df..a025074 100644 --- a/TurtleArt/tacollaboration.py +++ b/TurtleArt/tacollaboration.py @@ -202,11 +202,12 @@ class Collaboration(): try: command, payload = event_message.split('|', 2) - self._processing_methods[command](payload) except ValueError: - debug_output('Could not split event message.', + debug_output('Could not split event message [%s]' % event_message, self._tw.running_sugar) + self._processing_methods[command](payload) + # Restore active Turtle self._tw.canvas.set_turtle(self._tw.turtles.get_turtle_key( save_active_turtle)) diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py index 7a82a42..d1d9858 100644 --- a/TurtleArt/taconstants.py +++ b/TurtleArt/taconstants.py @@ -138,7 +138,7 @@ STATUS_SHAPES = ['status', 'info', 'nostack', 'dupstack', 'noinput', # Emulate Sugar toolbar when running from outside of Sugar # TOOLBAR_SHAPES = ['hideshowoff', 'eraseron', 'run-fastoff', - 'run-slowoff', 'debugoff', 'stopiton'] + 'run-slowoff', 'stopiton'] # # Legacy names diff --git a/TurtleArt/tasprite_factory.py b/TurtleArt/tasprite_factory.py index 97a303e..fb05666 100755 --- a/TurtleArt/tasprite_factory.py +++ b/TurtleArt/tasprite_factory.py @@ -426,76 +426,69 @@ class SVG: svg = "%s%s%s%s%s%s%s%s" % (" <path d=\"M 27.5 48.3 ", "C 26.9 48.3 26.4 48.2 25.9 48.2 L 27.2 50.5 L 28.6 48.2 ", - "C 28.2 48.2 27.9 48.3 27.5 48.3 Z\" stroke_width=\"3.5\" ", + "C 28.2 48.2 27.9 48.3 27.5 48.3 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") svg += "%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 40.2 11.7 ", "C 38.0 11.7 36.2 13.3 35.8 15.3 ", "C 37.7 16.7 39.3 18.4 40.5 20.5 ", "C 42.8 20.4 44.6 18.5 44.6 16.2 ", - "C 44.6 13.7 42.6 11.7 40.2 11.7 Z\" stroke_width=\"3.5\" ", + "C 44.6 13.7 42.6 11.7 40.2 11.7 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") svg += "%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 40.7 39.9 ", "C 39.5 42.1 37.9 44.0 35.9 45.4 ", "C 36.4 47.3 38.1 48.7 40.2 48.7 ", "C 42.6 48.7 44.6 46.7 44.6 44.3 ", - "C 44.6 42.0 42.9 40.2 40.7 39.9 Z\" stroke_width=\"3.5\" ", + "C 44.6 42.0 42.9 40.2 40.7 39.9 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") svg += "%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 14.3 39.9 ", "C 12.0 40.1 10.2 42.0 10.2 44.3 ", "C 10.2 46.7 12.2 48.7 14.7 48.7 ", "C 16.7 48.7 18.5 47.3 18.9 45.4 ", - "C 17.1 43.9 15.5 42.1 14.3 39.9 Z\" stroke_width=\"3.5\" ", + "C 17.1 43.9 15.5 42.1 14.3 39.9 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") svg += "%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 19.0 15.4 ", "C 18.7 13.3 16.9 11.7 14.7 11.7 ", "C 12.2 11.7 10.2 13.7 10.2 16.2 ", "C 10.2 18.5 12.1 20.5 14.5 20.6 ", - "C 15.7 18.5 17.2 16.8 19.0 15.4 Z\" stroke_width=\"3.5\" ", - "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") - svg += "%s%s%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 27.5 12.6 ", - "C 29.4 12.6 31.2 13.0 32.9 13.7 ", - "C 33.7 12.6 34.1 11.3 34.1 9.9 ", - "C 34.1 6.2 31.1 3.2 27.4 3.2 ", - "C 23.7 3.2 20.7 6.2 20.7 9.9 ", - "C 20.7 11.3 21.2 12.7 22.0 13.7 ", - "C 23.7 13.0 25.5 12.6 27.5 12.6 Z\" stroke_width=\"3.5\" ", + "C 15.7 18.5 17.2 16.8 19.0 15.4 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") + svg += '<path d="m 27.497,12.563 c 1.908,0 3.728,0.411 5.418,1.128 C 33.656,12.615 34.847526,11.272713 34.25,10 32.953704,7.2389259 31.1875,2.305074 27.5,2.305074 c -3.6875,0 -5.083333,4.9338519 -6.75,7.694926 -0.73796,1.222538 0.442,2.657 1.206,3.742 1.724,-0.749 3.587,-1.179 5.541,-1.179 z" style="fill:%s;stroke:%s;stroke-width:3.5" />' % (self._fill, self._stroke) svg += "%s%s%s%s%s%s%s%s%s%s%s%s" % (" <path d=\"M 43.1 30.4 ", "C 43.1 35.2 41.5 39.7 38.5 43.0 ", "C 35.6 46.4 31.6 48.3 27.5 48.3 ", "C 23.4 48.3 19.4 46.4 16.5 43.0 ", "C 13.5 39.7 11.9 35.2 11.9 30.4 ", "C 11.9 20.6 18.9 12.6 27.5 12.6 ", - "C 36.1 12.6 43.1 20.6 43.1 30.4 Z\" stroke_width=\"3.5\" ", + "C 36.1 12.6 43.1 20.6 43.1 30.4 Z\" stroke-width=\"3.5\" ", "fill=\"", self._fill, ";\" stroke=\"", self._stroke, "\" />\n") svg += "%s%s%s%s%s" % (" <path d=\"M 25.9 33.8 L 24.3 29.1 ", - "L 27.5 26.5 L 31.1 29.2 L 29.6 33.8 Z\" stroke_width=\"3.5\" ", + "L 27.5 26.5 L 31.1 29.2 L 29.6 33.8 Z\" stroke-width=\"3.5\" ", "fill=\"", self._stroke, ";\" stroke=\"none\" />\n") svg += "%s%s%s%s%s%s" % (" <path d=\"M 27.5 41.6 ", "C 23.5 41.4 22.0 39.5 22.0 39.5 L 25.5 35.4 L 30.0 35.5 ", "L 33.1 39.7 C 33.1 39.7 30.2 41.7 27.5 41.6 Z\" ", - "stroke_width=\"3.5\" fill=\"", self._stroke, + "stroke-width=\"3.5\" fill=\"", self._stroke, ";\" stroke=\"none\" />\n") svg += "%s%s%s%s%s%s" % (" <path d=\"M 18.5 33.8 ", "C 17.6 30.9 18.6 27.0 18.6 27.0 L 22.6 29.1 L 24.1 33.8 ", "L 20.5 38.0 C 20.5 38.0 19.1 36.0 18.4 33.8 Z\" ", - "stroke_width=\"3.5\" fill=\"", self._stroke, + "stroke-width=\"3.5\" fill=\"", self._stroke, ";\" stroke=\"none\" />\n") svg += "%s%s%s%s%s%s" % (" <path d=\"M 19.5 25.1 ", "C 19.5 25.1 20.0 23.2 22.5 21.3 ", "C 24.7 19.7 27.0 19.6 27.0 19.6 L 26.9 24.6 L 23.4 27.3 ", - "L 19.5 25.1 Z\" stroke_width=\"3.5\" fill=\"", self._stroke, + "L 19.5 25.1 Z\" stroke-width=\"3.5\" fill=\"", self._stroke, ";\" stroke=\"none\" />\n") svg += "%s%s%s%s%s%s" % (" <path d=\"M 32.1 27.8 L 28.6 25.0 ", "L 29 19.8 C 29 19.8 30.8 19.7 33.0 21.4 ", "C 35.2 23.2 36.3 26.4 36.3 26.4 L 32.1 27.8 Z\" ", - "stroke_width=\"3.5\" fill=\"", self._stroke, + "stroke-width=\"3.5\" fill=\"", self._stroke, ";\" stroke=\"none\" />\n") svg += "%s%s%s%s%s%s" % (" <path d=\"M 31.3 34.0 L 32.6 29.6 ", "L 36.8 28.0 C 36.8 28.0 37.5 30.7 36.8 33.7 ", "C 36.2 36.0 34.7 38.1 34.7 38.1 L 31.3 34.0 Z\" ", - "stroke_width=\"3.5\" fill=\"", self._stroke, + "stroke-width=\"3.5\" fill=\"", self._stroke, ";\" stroke=\"none\" />\n") self._width, self._height = 55, 55 svg += self.footer() diff --git a/TurtleArt/tautils.py b/TurtleArt/tautils.py index d60884e..e24d061 100644 --- a/TurtleArt/tautils.py +++ b/TurtleArt/tautils.py @@ -237,13 +237,12 @@ def data_from_string(text): ''' JSON load data from a string. ''' if type(text) == str: return json_load(text.replace(']],\n', ']], ')) + elif type(text) == unicode: + text = text.encode('ascii', 'replace') + return json_load(text.replace(']],\n', ']], ')) else: - print type(text), text - if hasattr('replace', text): - return json_load(text.replace(']],\n', ']], ')) - else: - print 'type error in data_from_string' - return '' + print 'type error (%s) in data_from_string' % (type(text)) + return None def data_to_file(data, ta_file): ''' Write data to a file. ''' diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 15a0b45..78b0d0b 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -1268,6 +1268,11 @@ class TurtleArtWindow(): # From the sprite at x, y, look for a corresponding block blk = self.block_list.spr_to_block(spr) + ''' If we were copying and didn't click on a block... ''' + if self.running_sugar and \ + (self.activity.copying or self.activity.sharing_blocks): + if blk is None or blk.type != 'block': + self.activity.restore_cursor() if blk is not None: if blk.type == 'block': self.selected_blk = blk @@ -1514,10 +1519,6 @@ class TurtleArtWindow(): self.lc.trace = 1 self.showblocks() self.run_button(3) - elif spr.name == 'debugoff': - self.lc.trace = 1 - self.showblocks() - self.run_button(6) elif spr.name == 'stopiton': self.stop_button() self.display_coordinates() @@ -1651,10 +1652,17 @@ class TurtleArtWindow(): self.drag_group = find_group(blk) (sx, sy) = blk.spr.get_xy() self.drag_pos = x - sx, y - sy - for blk in self.drag_group: - if blk.status != 'collapsed': - blk.spr.set_layer(TOP_LAYER) - blk.highlight() + if self.running_sugar and \ + (self.activity.copying or self.activity.sharing_blocks): + for blk in self.drag_group: + if blk.status != 'collapsed': + blk.spr.set_layer(TOP_LAYER) + blk.highlight() + self.block_operation = 'copying' + if self.activity.copying: + self.activity.send_to_clipboard() + else: + self.activity.share_blocks() if self.running_sugar and self._sharing and \ hasattr(self.activity, 'share_button'): self.activity.share_button.set_tooltip( @@ -2164,6 +2172,14 @@ class TurtleArtWindow(): abs(self.dx) < MOTION_THRESHOLD and \ abs(self.dy < MOTION_THRESHOLD))): self._click_block(x, y) + elif self.block_operation == 'copying': + gobject.timeout_add(500, self._unhighlight_drag_group, blk) + + def _unhighlight_drag_group(self, blk): + self.drag_group = find_group(blk) + for gblk in self.drag_group: + gblk.unhighlight() + self.drag_group = None def remote_turtle(self, name): ''' Is this a remote turtle? ''' @@ -2839,7 +2855,7 @@ class TurtleArtWindow(): return True if keyname in ['KP_End', 'End']: - self.run_button(0) + self.run_button(self.step_time) elif self.selected_spr is not None: if not self.lc.running and block_flag: blk = self.block_list.spr_to_block(self.selected_spr) diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py index 777bd79..778a7ad 100644 --- a/TurtleArtActivity.py +++ b/TurtleArtActivity.py @@ -558,6 +558,9 @@ class TurtleArtActivity(activity.Activity): self._make_project_buttons(self._toolbox.toolbar) + self._add_separator(self._toolbox.toolbar, expand=False, + visible=True) + self.keep_button = self._add_button( 'filesaveoff', _('Save snapshot'), self.do_keep_cb, self._toolbox.toolbar) @@ -868,6 +871,11 @@ class TurtleArtActivity(activity.Activity): else: # ...or else, load a Start Block onto the canvas. self.tw.load_start() + if self.has_toolbarbox: + self._old_cursor = self.get_window().get_cursor() + self.copying = False + self.sharing_blocks = False + def _setup_sharing(self): ''' Setup the Collabora stack. ''' self._collaboration = Collaboration(self.tw, self) @@ -1096,8 +1104,26 @@ in order to use the plugin.')) error_handler=self._internal_jobject_error_cb) self._jobject.destroy() + def restore_cursor(self): + ''' No longer copying or sharing, so restore standard cursor. ''' + self.copying = False + self.sharing_blocks = False + if self.has_toolbarbox: + self.get_window().set_cursor(self._old_cursor) + def _copy_cb(self, button): ''' Copy to the clipboard. ''' + if self.copying: + self.restore_cursor() + else: + self.copying = True + if self.has_toolbarbox: + self._old_cursor = self.get_window().get_cursor() + self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1)) + + def send_to_clipboard(self): + ''' Send selected stack to clipboard. ''' + self.restore_cursor() clipboard = gtk.Clipboard() _logger.debug('Serialize the project and copy to clipboard.') data = self.tw.assemble_data_to_save(False, False) @@ -1106,20 +1132,10 @@ in order to use the plugin.')) clipboard.set_text(text) self.tw.paste_offset = 20 - def _share_cb(self, button): - ''' Share a stack of blocks. ''' - if not self.tw.sharing(): - return - _logger.debug('Serialize a stack and send as event.') - data = self.tw.assemble_data_to_save(False, False) - if data is not []: - text = data_to_string(data) - event = 'B|%s' % (data_to_string([self.tw.nick, text])) # Paste - self.tw.send_event(event) - self.tw.paste_offset = 20 - def _paste_cb(self, button): ''' Paste from the clipboard. ''' + if self.copying: + self.restore_cursor() clipboard = gtk.Clipboard() _logger.debug('Paste to the project.') text = clipboard.wait_for_text() @@ -1134,6 +1150,29 @@ in order to use the plugin.')) self.tw.paste_offset) self.tw.paste_offset += 20 + def _share_cb(self, button): + ''' Share a stack of blocks. ''' + if self.sharing_blocks: + self.restore_cursor() + else: + self.sharing_blocks = True + if self.has_toolbarbox: + self._old_cursor = self.get_window().get_cursor() + self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND1)) + + def share_blocks(self): + ''' Share selected stack. ''' + if not self.tw.sharing(): + return + _logger.debug('Serialize a stack and send as event.') + self.restore_cursor() + data = self.tw.assemble_data_to_save(False, False) + if data is not []: + text = data_to_string(data) + event = 'B|%s' % (data_to_string([self.tw.nick, text])) # Paste + self.tw.send_event(event) + self.tw.paste_offset = 20 + def _add_label(self, string, toolbar, width=None): ''' Add a label to a toolbar. ''' label = gtk.Label(string) diff --git a/activity/activity.info b/activity/activity.info index 017d1ee..6d6c73d 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -1,6 +1,6 @@ [Activity] name = Turtle Art -activity_version = 147 +activity_version = 148 license = MIT bundle_id = org.laptop.TurtleArtActivity exec = sugar-activity TurtleArtActivity.TurtleArtActivity |