diff options
Diffstat (limited to 'TurtleArt/tawindow.py')
-rw-r--r-- | TurtleArt/tawindow.py | 488 |
1 files changed, 290 insertions, 198 deletions
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 6152f20..50691c8 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -58,7 +58,7 @@ from taconstants import (HORIZONTAL_PALETTE, VERTICAL_PALETTE, BLOCK_SCALE, PYTHON_SKIN, PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK, EXPANDABLE_ARGS, XO1, XO15, XO175, XO30, XO4, TITLEXY, CONTENT_ARGS, CONSTANTS, EXPAND_SKIN, PROTO_LAYER, - EXPANDABLE_FLOW, SUFFIX) + EXPANDABLE_FLOW, SUFFIX, TMP_SVG_PATH) from tapalette import (palette_names, palette_blocks, expandable_blocks, block_names, content_blocks, default_values, special_names, block_styles, help_strings, @@ -99,9 +99,16 @@ _MACROS_SUBPATH = 'macros' class TurtleArtWindow(): ''' TurtleArt Window class abstraction ''' - def __init__(self, canvas_window, path, parent=None, + def __init__(self, canvas_window, path, parent=None, activity=None, mycolors=None, mynick=None, turtle_canvas=None, - running_sugar=True): + running_sugar=True, running_turtleart=True): + ''' + parent: the GTK Window that TA runs in + activity: the object that instantiated this TurtleArtWindow (in + GNOME, a TurtleMain instance, in Sugar, the Activity + instance) + running_turtleart: are we running TA or exported python code? + ''' self.parent = parent self.turtle_canvas = turtle_canvas self._loaded_project = '' @@ -111,6 +118,7 @@ class TurtleArtWindow(): self.gst_available = _GST_AVAILABLE self.running_sugar = False self.nick = None + self.running_turtleart = running_turtleart if isinstance(canvas_window, gtk.DrawingArea): self.interactive_mode = True self.window = canvas_window @@ -135,8 +143,13 @@ class TurtleArtWindow(): self.interactive_mode = False self.window = canvas_window self.running_sugar = False - self.activity = parent + if activity is not None: + self.activity = activity + else: + self.activity = parent + + # loading and saving self.path = path self.load_save_folder = os.path.join(path, 'samples') self.py_load_save_folder = os.path.join(path, 'pysamples') @@ -144,6 +157,8 @@ class TurtleArtWindow(): self.used_block_list = [] # Which blocks has the user used? self.save_folder = None self.save_file_name = None + + # dimensions self.width = gtk.gdk.screen_width() self.height = gtk.gdk.screen_height() self.rect = gtk.gdk.Rectangle(0, 0, 0, 0) @@ -166,6 +181,7 @@ class TurtleArtWindow(): self.sharing_blocks = False self.deleting_blocks = False + # find out which character to use as decimal point try: locale.setlocale(locale.LC_NUMERIC, '') except locale.Error: @@ -174,8 +190,8 @@ class TurtleArtWindow(): if self.decimal_point == '' or self.decimal_point is None: self.decimal_point = '.' + # settings that depend on the hardware self.orientation = HORIZONTAL_PALETTE - self.hw = get_hardware() self.lead = 1.0 if self.hw in (XO1, XO15, XO175, XO4): @@ -200,8 +216,9 @@ class TurtleArtWindow(): self.nop = 'nop' self.loaded = 0 self.step_time = 0 - self.hide = False - self.palette = True + # show/ hide palettes depending on whether we're running in TA or not + self.hide = not self.running_turtleart + self.palette = self.running_turtleart self.coord_scale = 1 self.buddies = [] self._saved_string = '' @@ -239,6 +256,7 @@ class TurtleArtWindow(): self.turtle_movement_to_share = None self.paste_offset = 20 # Don't paste on top of where you copied. + # common properties of all blocks (font size, decimal point, ...) self.block_list = Blocks(font_scale_factor=self.scale, decimal_point=self.decimal_point) if self.interactive_mode: @@ -246,23 +264,24 @@ class TurtleArtWindow(): else: self.sprite_list = None + # canvas object that supports the basic drawing functionality self.canvas = TurtleGraphics(self, self.width, self.height) if self.hw == XO175 and self.canvas.width == 1024: self.hw = XO30 if self.interactive_mode: self.sprite_list.set_cairo_context(self.canvas.canvas) - self.turtles = Turtles(self.sprite_list) - if self.nick is None: - self.default_turtle_name = DEFAULT_TURTLE - else: - self.default_turtle_name = self.nick + self.turtles = Turtles(self) + if self.nick is not None: + self.turtles.set_default_turtle_name(self.nick) if mycolors is None: - Turtle(self.turtles, self.default_turtle_name) + Turtle(self.turtles, self.turtles.get_default_turtle_name()) else: - Turtle(self.turtles, self.default_turtle_name, mycolors.split(',')) - self.active_turtle = self.turtles.get_turtle(self.default_turtle_name) - self.active_turtle.show() + Turtle(self.turtles, self.turtles.get_default_turtle_name(), + mycolors.split(',')) + self.turtles.set_active_turtle( + self.turtles.get_turtle(self.turtles.get_default_turtle_name())) + self.turtles.get_active_turtle().show() self.canvas.clearscreen(False) @@ -276,8 +295,10 @@ class TurtleArtWindow(): self.saved_pictures = [] self.block_operation = '' - from tabasics import Palettes - self._basic_palettes = Palettes(self) + # only in TA: setup basic palettes + if self.running_turtleart: + from tabasics import Palettes + self._basic_palettes = Palettes(self) if self.interactive_mode: gobject.idle_add(self._lazy_init) @@ -289,16 +310,20 @@ class TurtleArtWindow(): self._init_plugins() self._setup_plugins() self._setup_misc() - for name in palette_init_on_start: - debug_output('initing palette %s' % (name), self.running_sugar) - self.show_toolbar_palette(palette_names.index(name), - init_only=False, regenerate=True, - show=False) - self._basic_palettes.make_trash_palette() + if self.running_turtleart: + self._basic_palettes.make_trash_palette() + for name in palette_init_on_start: + debug_output('initing palette %s' % (name), self.running_sugar) + self.show_toolbar_palette(palette_names.index(name), + init_only=False, + regenerate=True, + show=False) - self.show_toolbar_palette(0, init_only=False, regenerate=True, - show=True) + self.show_toolbar_palette(0, + init_only=False, + regenerate=True, + show=True) if self.running_sugar: self.activity.check_buttons_for_fit() @@ -331,7 +356,7 @@ class TurtleArtWindow(): pname = os.path.join(path, dirname, dirname + '.py') if os.path.exists(pname): plugin_files.append(dirname) - return plugin_files + return plugin_files def _init_plugins(self): ''' Try importing plugin files from the plugin dir. ''' @@ -342,7 +367,7 @@ class TurtleArtWindow(): def init_plugin(self, plugin_dir): ''' Initialize plugin in plugin_dir ''' plugin_class = plugin_dir.capitalize() - f = "def f(self): from plugins.%s.%s import %s; return %s(self)" \ + f = 'def f(self): from plugins.%s.%s import %s; return %s(self)' \ % (plugin_dir, plugin_dir, plugin_class, plugin_class) plugins = {} # NOTE: When debugging plugins, it may be useful to not trap errors @@ -418,15 +443,15 @@ class TurtleArtWindow(): self.window.add_events(gtk.gdk.BUTTON_RELEASE_MASK) self.window.add_events(gtk.gdk.POINTER_MOTION_MASK) self.window.add_events(gtk.gdk.KEY_PRESS_MASK) - self.window.connect("expose-event", self._expose_cb) - self.window.connect("button-press-event", self._buttonpress_cb) - self.window.connect("button-release-event", self._buttonrelease_cb) - self.window.connect("motion-notify-event", self._move_cb) - self.window.connect("key-press-event", self._keypress_cb) + self.window.connect('expose-event', self._expose_cb) + self.window.connect('button-press-event', self._buttonpress_cb) + self.window.connect('button-release-event', self._buttonrelease_cb) + self.window.connect('motion-notify-event', self._move_cb) + self.window.connect('key-press-event', self._keypress_cb) gtk.gdk.screen_get_default().connect('size-changed', self._configure_cb) - target = [("text/plain", 0, 0)] + target = [('text/plain', 0, 0)] self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, target, gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE) self.window.connect('drag_data_received', self._drag_data_received) @@ -506,16 +531,20 @@ class TurtleArtWindow(): self._autohide_shape = True for name in OVERLAY_SHAPES: + if name == 'Cartesian': + continue self.overlay_shapes[name] = Sprite( self.sprite_list, int(self.width / 2 - 600), int(self.height / 2 - 450), svg_str_to_pixbuf( - svg_from_file("%s/images/%s.svg" % (self.path, name)))) + svg_from_file('%s/images/%s.svg' % (self.path, name)))) self.overlay_shapes[name].hide() self.overlay_shapes[name].type = 'overlay' - if not self.running_sugar: + self._create_scaled_cartesian_coordinates() + + if self.running_turtleart and not self.running_sugar: # offset = 2 * self.width - 55 * len(TOOLBAR_SHAPES) offset = 55 * (1 + len(palette_blocks)) for i, name in enumerate(TOOLBAR_SHAPES): @@ -530,6 +559,27 @@ class TurtleArtWindow(): self.toolbar_shapes[name].type = 'toolbar' self.toolbar_shapes['stopiton'].hide() + def _create_scaled_cartesian_coordinates(self): + # Cartesian overlay has to be scaled to match the coordinate_scale + # 200 pixels in the graphic == height / 4. (10 units) + pixbuf = svg_str_to_pixbuf( + svg_from_file('%s/images/%s.svg' % (self.path, 'Cartesian'))) + + if self.running_sugar: + scale = self.height / 800. + else: + scale = self.height / 800. + # scale = (self.height + ICON_SIZE) / 800. + self.overlay_shapes['Cartesian'] = Sprite( + self.sprite_list, + int(self.width / 2 - 600), + int(self.height / 2 - 450), + pixbuf.scale_simple(int(1200 * scale), + int(900 * scale), + gtk.gdk.INTERP_BILINEAR)) + self.overlay_shapes['Cartesian'].set_layer(TAB_LAYER) + self.overlay_shapes['Cartesian'].hide() + def set_sharing(self, shared): self._sharing = shared @@ -625,7 +675,7 @@ class TurtleArtWindow(): if find_start_stack(blk): self.step_time = time if self.running_sugar: - debug_output("running stack starting from %s" % (blk.name), + debug_output('running stack starting from %s' % (blk.name), self.running_sugar) if running_from_button_push: self.selected_blk = None @@ -639,7 +689,7 @@ class TurtleArtWindow(): if find_block_to_run(blk): self.step_time = time if self.running_sugar: - debug_output("running stack starting from %s" % (blk.name), + debug_output('running stack starting from %s' % (blk.name), self.running_sugar) if running_from_button_push: self.selected_blk = None @@ -686,20 +736,27 @@ class TurtleArtWindow(): def draw_overlay(self, overlay): ''' Draw a coordinate grid onto the canvas. ''' - save_heading = self.canvas.heading - self.canvas.heading = 0 - w = self.overlay_shapes[overlay].rect[2] - h = self.overlay_shapes[overlay].rect[3] + width = self.overlay_shapes[overlay].rect[2] + height = self.overlay_shapes[overlay].rect[3] + if self.running_sugar: + y_offset = 0 + else: + y_offset = 0 + # y_offset = ICON_SIZE self.canvas.draw_surface( self.overlay_shapes[overlay].cached_surfaces[0], - (self.canvas.width - w) / 2., - (self.canvas.height - h) / 2., w, h) - self.canvas.heading = save_heading + (self.canvas.width - width) / 2.0, + (self.canvas.height - height + y_offset) / 2.0, + width, + height) - def update_overlay_position(self, widget, event): + def update_overlay_position(self, widget=None, event=None): ''' Reposition the overlays when window size changes ''' - self.width = event.width - self.height = event.height + # self.width = event.width + # self.height = event.height + self.width = gtk.gdk.screen_width() + self.height = gtk.gdk.screen_height() + for name in OVERLAY_SHAPES: if not name in self.overlay_shapes: continue @@ -708,23 +765,30 @@ class TurtleArtWindow(): if shape in shape._sprites.list: shape.hide() showing = True + self.overlay_shapes[name].move((int(self.width / 2 - 600), + int(self.height / 2 - 450))) + ''' self.overlay_shapes[name] = Sprite( self.sprite_list, int(self.width / 2 - 600), int(self.height / 2 - 450), svg_str_to_pixbuf( - svg_from_file("%s/images/%s.svg" % (self.path, name)))) + svg_from_file('%s/images/%s.svg' % (self.path, name)))) + ''' if showing: self.overlay_shapes[name].set_layer(OVERLAY_LAYER) else: self.overlay_shapes[name].hide() + ''' self.overlay_shapes[name].type = 'overlay' + ''' + self.cartesian = False self.polar = False self.metric = False self.canvas.width = self.width self.canvas.height = self.height - self.canvas.move_turtle() + self.turtles.get_active_turtle().move_turtle() def hideshow_button(self): ''' Hide/show button ''' @@ -776,6 +840,7 @@ class TurtleArtWindow(): if not self.running_sugar or not self.activity.has_toolbarbox: self.toolbar_spr.set_layer(CATEGORY_LAYER) self.palette = True + self._set_coordinates_label(palette_names[n]) def hide_palette(self): ''' Hide the palette. ''' @@ -1064,7 +1129,7 @@ class TurtleArtWindow(): self.toolbar_offset, svg_str_to_pixbuf( svg_from_file( - "%s/images/palettehorizontal.svg" % (self.path))))) + '%s/images/palettehorizontal.svg' % (self.path))))) self.palette_button.append( Sprite( self.sprite_list, @@ -1072,7 +1137,7 @@ class TurtleArtWindow(): self.toolbar_offset, svg_str_to_pixbuf( svg_from_file( - "%s/images/palettevertical.svg" % (self.path))))) + '%s/images/palettevertical.svg' % (self.path))))) self.palette_button[0].name = _('orientation') self.palette_button[1].name = _('orientation') self.palette_button[0].type = 'palette' @@ -1087,7 +1152,7 @@ class TurtleArtWindow(): self.toolbar_offset, svg_str_to_pixbuf( svg_from_file( - "%s/images/palettenext.svg" % (self.path))))) + '%s/images/palettenext.svg' % (self.path))))) self.palette_button[2].name = _('next') self.palette_button[2].type = 'palette' self.palette_button[2].set_layer(TAB_LAYER) @@ -1101,7 +1166,7 @@ class TurtleArtWindow(): self.toolbar_offset + dims[1], svg_str_to_pixbuf( svg_from_file( - "%s/images/palettehshift.svg" % (self.path))))) + '%s/images/palettehshift.svg' % (self.path))))) self.palette_button.append( Sprite( self.sprite_list, @@ -1109,7 +1174,7 @@ class TurtleArtWindow(): self.toolbar_offset, svg_str_to_pixbuf( svg_from_file( - "%s/images/palettevshift.svg" % (self.path))))) + '%s/images/palettevshift.svg' % (self.path))))) self.palette_button.append( Sprite( self.sprite_list, @@ -1117,7 +1182,7 @@ class TurtleArtWindow(): self.toolbar_offset + dims[1], svg_str_to_pixbuf( svg_from_file( - "%s/images/palettehshift2.svg" % (self.path))))) + '%s/images/palettehshift2.svg' % (self.path))))) self.palette_button.append( Sprite( self.sprite_list, @@ -1125,7 +1190,7 @@ class TurtleArtWindow(): self.toolbar_offset, svg_str_to_pixbuf( svg_from_file( - "%s/images/palettevshift2.svg" % (self.path))))) + '%s/images/palettevshift2.svg' % (self.path))))) for i in range(4): self.palette_button[3 + i].name = _('shift') self.palette_button[3 + i].type = 'palette' @@ -1384,6 +1449,13 @@ class TurtleArtWindow(): if spr is not None: blk = self.block_list.spr_to_block(spr) if blk is not None: + # Make sure stop button is visible + if self.running_sugar: + self.activity.stop_turtle_button.set_icon("stopiton") + self.activity.stop_turtle_button.set_tooltip( + _('Stop turtle')) + elif self.interactive_mode: + self.toolbar_shapes['stopiton'].set_layer(TAB_LAYER) self.showlabel('status', label=_('Please hit the Stop Button \ before making changes to your Turtle Blocks program')) @@ -1691,13 +1763,13 @@ before making changes to your Turtle Blocks program')) def _look_for_a_turtle(self, spr, x, y): # Next, look for a turtle - t = self.turtles.spr_to_turtle(spr) - if t is not None: + turtle = self.turtles.spr_to_turtle(spr) + if turtle is not None: # If turtle is shared, ignore click - if self.remote_turtle(t.get_name()): + if self.remote_turtle(turtle.get_name()): return True - self.selected_turtle = t - self.canvas.set_turtle(self.turtles.get_turtle_key(t)) + self.selected_turtle = turtle + self.turtles.set_turtle(self.turtles.get_turtle_key(turtle)) self._turtle_pressed(x, y) self.update_counter = 0 return True @@ -2245,7 +2317,7 @@ before making changes to your Turtle Blocks program')) self.used_block_list.append(newblk.spr.labels[0]) def new_macro(self, name, x, y): - ''' Create a "macro" (predefined stack of blocks). ''' + ''' Create a 'macro' (predefined stack of blocks). ''' macro = MACROS[name] macro[0][2] = x macro[0][3] = y @@ -2295,7 +2367,7 @@ before making changes to your Turtle Blocks program')) else: cons.append(blocks[c]) else: - debug_output("connection error %s" % + debug_output('connection error %s' % (str(self._process_block_data[i])), self.running_sugar) cons.append(None) @@ -2322,7 +2394,7 @@ before making changes to your Turtle Blocks program')) blocks[c].connections[3] = None else: # Connection was to a block we haven't seen yet. - debug_output("Warning: dock to the future", + debug_output('Warning: dock to the future', self.running_sugar) else: if self._process_block_data[i][4][0] is not None: @@ -2338,10 +2410,10 @@ before making changes to your Turtle Blocks program')) blocks[c].connections[1] = None else: # Connection was to a block we haven't seen yet. - debug_output("Warning: dock to the future", + debug_output('Warning: dock to the future', self.running_sugar) else: - debug_output("Warning: unknown connection state %s" % + debug_output('Warning: unknown connection state %s' % (str(blk.connections)), self.running_sugar) blk.connections = cons[:] @@ -2410,20 +2482,22 @@ before making changes to your Turtle Blocks program')) self._adjust_dock_positions(c) def _turtle_pressed(self, x, y): - (tx, ty) = self.selected_turtle.get_xy() - w = self.selected_turtle.spr.rect.width / 2 - h = self.selected_turtle.spr.rect.height / 2 - dx = x - tx - w - dy = y - ty - h - # if x, y is near the edge, rotate + pos = self.selected_turtle.get_xy() + tpos = self.turtles.turtle_to_screen_coordinates(pos) + dx = x - tpos[0] + dy = y - tpos[1] if not hasattr(self.lc, 'value_blocks'): self.lc.find_value_blocks() self.lc.update_values = True - if (dx * dx) + (dy * dy) > ((w * w) + (h * h)) / 6: - self.drag_turtle = \ - ('turn', self.canvas.heading - atan2(dy, dx) / DEGTOR, 0) + # Compare distance squared of drag position to sprite radius. + # If x, y is near the edge, rotate. + if (dx * dx) + (dy * dy) > self.selected_turtle.get_drag_radius(): + self.drag_turtle = ( + 'turn', + self.selected_turtle.get_heading() - atan2(dy, dx) / DEGTOR, + 0) else: - self.drag_turtle = ('move', x - tx, y - ty) + self.drag_turtle = ('move', x - tpos[0], y - tpos[1]) def _move_cb(self, win, event): x, y = xy(event) @@ -2436,18 +2510,18 @@ before making changes to your Turtle Blocks program')) ''' Share turtle movement and rotation after button up ''' if self.sharing(): nick = self.turtle_movement_to_share.get_name() - self.send_event("r|%s" % - (data_to_string([nick, - round_int(self.canvas.heading)]))) - if self.canvas.pendown: + self.send_event('r|%s' % (data_to_string( + [nick, + round_int(self.turtles.get_active_turtle().get_heading())]))) + if self.turtles.get_active_turtle().get_pen_state(): self.send_event('p|%s' % (data_to_string([nick, False]))) put_pen_back_down = True else: put_pen_back_down = False - self.send_event("x|%s" % - (data_to_string([nick, - [round_int(self.canvas.xcor), - round_int(self.canvas.ycor)]]))) + self.send_event('x|%s' % (data_to_string( + [nick, + [round_int(self.turtles.get_active_turtle().get_xy()[0]), + round_int(self.turtles.get_active_turtle().get_xy()[1])]]))) if put_pen_back_down: self.send_event('p|%s' % (data_to_string([nick, True]))) self.turtle_movement_to_share = None @@ -2474,34 +2548,37 @@ before making changes to your Turtle Blocks program')) # First, check to see if we are dragging or rotating a turtle. if self.selected_turtle is not None: - dtype, dragx, dragy = self.drag_turtle - (sx, sy) = self.selected_turtle.get_xy() - # self.canvas.set_turtle(self.selected_turtle.get_name()) + drag_type, dragx, dragy = self.drag_turtle self.update_counter += 1 - if dtype == 'move': - dx = x - dragx - sx + self.selected_turtle.spr.rect.width / 2 - dy = y - dragy - sy + self.selected_turtle.spr.rect.height / 2 + if drag_type == 'move': + dx = x - dragx + dy = y - dragy self.selected_turtle.spr.set_layer(TOP_LAYER) - tx, ty = self.canvas.screen_to_turtle_coordinates(sx + dx, - sy + dy) - if self.canvas.pendown: - self.canvas.setpen(False) - self.canvas.setxy(tx, ty, share=False) - self.canvas.setpen(True) + pos = self.turtles.screen_to_turtle_coordinates((dx, dy)) + if self.selected_turtle.get_pen_state(): + self.selected_turtle.set_pen_state(False) + self.selected_turtle.set_xy(pos, share=False, dragging=True) + self.selected_turtle.set_pen_state(True) else: - self.canvas.setxy(tx, ty, share=False) + self.selected_turtle.set_xy(pos, share=False, dragging=True) if self.update_counter % 5: self.lc.update_label_value( - 'xcor', self.canvas.xcor / self.coord_scale) + 'xcor', self.selected_turtle.get_xy()[0] / + self.coord_scale) self.lc.update_label_value( - 'ycor', self.canvas.ycor / self.coord_scale) + 'ycor', self.selected_turtle.get_xy()[1] / + self.coord_scale) else: - dx = x - sx - self.selected_turtle.spr.rect.width / 2 - dy = y - sy - self.selected_turtle.spr.rect.height / 2 - self.canvas.seth(int(dragx + atan2(dy, dx) / DEGTOR + 5) / - 10 * 10, share=False) + spos = self.turtles.turtle_to_screen_coordinates( + self.selected_turtle.get_xy()) + dx = x - spos[0] + dy = y - spos[1] + self.turtles.get_active_turtle().set_heading( + int(dragx + atan2(dy, dx) / DEGTOR + 5) / 10 * 10, + share=False) if self.update_counter % 5: - self.lc.update_label_value('heading', self.canvas.heading) + self.lc.update_label_value( + 'heading', self.selected_turtle.get_heading()) if self.update_counter % 20: self.display_coordinates() self.turtle_movement_to_share = self.selected_turtle @@ -2658,30 +2735,26 @@ before making changes to your Turtle Blocks program')) # We may have been moving the turtle if self.selected_turtle is not None: - (tx, ty) = self.selected_turtle.get_xy() - k = self.turtles.get_turtle_key(self.selected_turtle) - + pos = self.selected_turtle.get_xy() + spos = self.turtles.turtle_to_screen_coordinates(pos) + turtle_name = self.turtles.get_turtle_key(self.selected_turtle) # Remove turtles by dragging them onto the trash palette. - if self._in_the_trash(tx, ty): + if self._in_the_trash(spos[0], spos[1]): # If it is the default turtle, just recenter it. - if k == self.default_turtle_name: + if turtle_name == self.turtles.get_default_turtle_name(): self._move_turtle(0, 0) - self.canvas.heading = 0 - self.canvas.turn_turtle() - self.lc.update_label_value('heading', self.canvas.heading) + self.selected_turtle.set_heading(0) + self.lc.update_label_value('heading', 0) else: self.selected_turtle.hide() - self.turtles.remove_from_dict(k) - self.active_turtle = None + self.turtles.remove_from_dict(turtle_name) + self.turtles.set_active_turtle(None) else: - self._move_turtle( - tx - self.canvas.width / 2. + - self.active_turtle.spr.rect.width / 2., - self.canvas.height / 2. - ty - - self.active_turtle.spr.rect.height / 2.) + self._move_turtle(pos[0], pos[1]) + self.selected_turtle = None - if self.active_turtle is None: - self.canvas.set_turtle(self.default_turtle_name) + if self.turtles.get_active_turtle() is None: + self.turtles.set_turtle(self.turtles.get_default_turtle_name()) self.display_coordinates() return @@ -2757,21 +2830,23 @@ before making changes to your Turtle Blocks program')) turtle.label_block.spr.set_label(name[0:4] + '…') else: turtle.label_block.spr.set_label(name) + turtle.set_remote() turtle.show() def _move_turtle(self, x, y): ''' Move the selected turtle to (x, y). ''' - self.canvas.xcor = x - self.canvas.ycor = y - self.canvas.move_turtle() + if self.drag_turtle[0] == 'move': + self.turtles.get_active_turtle().move_turtle((x, y)) if self.interactive_mode: self.display_coordinates() if self.running_sugar: self.selected_turtle.spr.set_layer(TURTLE_LAYER) - self.lc.update_label_value('xcor', - self.canvas.xcor / self.coord_scale) - self.lc.update_label_value('ycor', - self.canvas.ycor / self.coord_scale) + self.lc.update_label_value( + 'xcor', self.turtles.get_active_turtle().get_xy()[0] / + self.coord_scale) + self.lc.update_label_value( + 'ycor', self.turtles.get_active_turtle().get_xy()[1] / + self.coord_scale) def _click_block(self, x, y): ''' Click block: lots of special cases to handle... ''' @@ -3043,10 +3118,8 @@ before making changes to your Turtle Blocks program')) if blk is None: return self.lc.find_value_blocks() # Are there blocks to update? - # Is there a savesvg block? - if len(self.block_list.get_similar_blocks('block', 'savesvg')) > 0: - if self.canvas.cr_svg is None: - self.canvas.setup_svg_surface() + if self.canvas.cr_svg is None: + self.canvas.setup_svg_surface() self.running_blocks = True self._start_plugins() # Let the plugins know we are running. top = find_top_block(blk) @@ -3328,7 +3401,7 @@ before making changes to your Turtle Blocks program')) else: dy += delta gblk = gblk.connections[-1] - # Clamp has room for one "standard" block by default + # Clamp has room for one 'standard' block by default if dy > 0: dy -= 21 # Fixme: don't hardcode if blk.name in block_styles['clamp-style-else'] and dockn == 3: @@ -3456,7 +3529,7 @@ before making changes to your Turtle Blocks program')) self.keypress = keyname if alt_mask: - if keyname == "p": + if keyname == 'p': self.hideshow_button() elif keyname == 'q': self.quit_plugins() @@ -3526,13 +3599,15 @@ before making changes to your Turtle Blocks program')) def _jog_turtle(self, dx, dy): ''' Jog turtle ''' if dx == -1 and dy == -1: - self.canvas.xcor = 0 - self.canvas.ycor = 0 + x = 0 + y = 0 else: - self.canvas.xcor += dx - self.canvas.ycor += dy - self.active_turtle = self.turtles.spr_to_turtle(self.selected_spr) - self.canvas.move_turtle() + pos = self.turtles.get_active_turtle().get_xy() + x = pos[0] + dx + y = pos[1] + dy + self.turtles.set_active_turtle( + self.turtles.spr_to_turtle(self.selected_spr)) + self.turtles.get_active_turtle().move_turtle((x, y)) self.display_coordinates() self.selected_turtle = None @@ -3604,15 +3679,15 @@ before making changes to your Turtle Blocks program')) num = float(text.replace(self.decimal_point, '.')) if num > 1000000: num = 1 - self.showlabel("#overflowerror") + self.showlabel('#overflowerror') elif num < -1000000: num = -1 - self.showlabel("#overflowerror") + self.showlabel('#overflowerror') if int(num) == num: num = int(num) except ValueError: num = 0 - self.showlabel("#notanumber") + self.showlabel('#notanumber') else: num = 0 self.selected_blk.spr.set_label(str(num)) @@ -3664,7 +3739,7 @@ before making changes to your Turtle Blocks program')) f.close() id = fname except IOError: - error_output("Unable to read Python code from %s" % (fname), + error_output('Unable to read Python code from %s' % (fname), self.running_sugar) return id @@ -3686,20 +3761,20 @@ before making changes to your Turtle Blocks program')) try: datastore.write(dsobject) id = dsobject.object_id - debug_output("Copied %s to the datastore" % (fname), + debug_output('Copied %s to the datastore' % (fname), self.running_sugar) # Don't copy the same file more than once self._py_cache[fname] = id except IOError: - error_output("Error copying %s to the datastore" % (fname), + error_output('Error copying %s to the datastore' % (fname), self.running_sugar) id = None dsobject.destroy() if add_new_block: # add a new block for this code at turtle position - (tx, ty) = self.active_turtle.get_xy() - self._new_block('userdefined', tx, ty) + pos = self.turtles.get_active_turtle().get_xy() + self._new_block('userdefined', pos[0], pos[1]) self.myblock[self.block_list.list.index(self.drag_group[0])] =\ self.python_code self.set_userdefined(self.drag_group[0]) @@ -3725,11 +3800,11 @@ before making changes to your Turtle Blocks program')) if dsobject is None: return try: - file_handle = open(dsobject.file_path, "r") + file_handle = open(dsobject.file_path, 'r') self.python_code = file_handle.read() file_handle.close() except IOError: - debug_output("couldn't open %s" % dsobject.file_path, + debug_output('Could not open %s' % dsobject.file_path, self.running_sugar) # Save the object id as the block value if blk is None: @@ -3745,7 +3820,6 @@ before making changes to your Turtle Blocks program')) if self.running_sugar: chooser_dialog(self.parent, 'org.laptop.Pippy', self.load_python_code_from_journal) - dsobject.destroy() else: self.load_python_code_from_file(fname=None, add_new_block=False) @@ -3757,7 +3831,7 @@ before making changes to your Turtle Blocks program')) def new_project(self): ''' Start a new project ''' self.lc.stop_logo() - self._loaded_project = "" + self._loaded_project = '' # Put current project in the trash. while len(self.just_blocks()) > 0: blk = self.just_blocks()[0] @@ -3768,7 +3842,7 @@ before making changes to your Turtle Blocks program')) def is_new_project(self): ''' Is this a new project or was a old project loaded from a file? ''' - return self._loaded_project == "" + return self._loaded_project == '' def project_has_changed(self): ''' WARNING: order of JSON serialized data may have changed. ''' @@ -3777,11 +3851,10 @@ before making changes to your Turtle Blocks program')) saved_project_data = f.read() f.close() except: - debug_output("problem loading saved project data from %s" % + debug_output('problem loading saved project data from %s' % (self._loaded_project), self.running_sugar) - saved_project_data = "" + saved_project_data = '' current_project_data = data_to_string(self.assemble_data_to_save()) - return saved_project_data != current_project_data def load_files(self, ta_file, create_new_project=True): @@ -3825,12 +3898,13 @@ before making changes to your Turtle Blocks program')) def load_turtle(self, blk, key=1): ''' Restore a turtle from its saved state ''' tid, name, xcor, ycor, heading, color, shade, pensize = blk - self.canvas.set_turtle(key) - self.canvas.setxy(xcor, ycor, pendown=False) - self.canvas.seth(heading) - self.canvas.setcolor(color) - self.canvas.setshade(shade) - self.canvas.setpensize(pensize) + self.turtles.set_turtle(key) + self.turtles.get_active_turtle().set_xy(xcor, ycor, pendown=False) + self.turtles.get_active_turtle().set_heading(heading) + self.turtles.get_active_turtle().set_color(color) + self.turtles.get_active_turtle().set_shade(shade) + self.turtles.get_active_turtle().set_gray(100) + self.turtles.get_active_turtle().set_pen_size(pensize) def load_block(self, b, offset=0): ''' Restore individual blocks from saved state ''' @@ -3933,8 +4007,8 @@ before making changes to your Turtle Blocks program')) btype = OLD_NAMES[btype] blk = Block(self.block_list, self.sprite_list, btype, - b[2] + self.canvas.cx + offset, - b[3] + self.canvas.cy + offset, + b[2] + offset, + b[3] + offset, 'block', values, self.block_scale) # If it was an unknown block type, we need to match the number @@ -3966,7 +4040,7 @@ before making changes to your Turtle Blocks program')) dsobject = datastore.get(value) except: # Should be IOError, but dbus error is raised dsobject = None - debug_output("couldn't get dsobject %s" % (value), + debug_output('Could not get dsobject %s' % (value), self.running_sugar) if dsobject is not None: self.load_python_code_from_journal(dsobject, blk) @@ -4018,7 +4092,7 @@ before making changes to your Turtle Blocks program')) x, y = self._calc_image_offset('', blk.spr) blk.set_image(pixbuf, x, y) except: - debug_output("Couldn't open dsobject (%s)" % + debug_output('Could not open dsobject (%s)' % (blk.values[0]), self.running_sugar) self._block_skin('journaloff', blk) else: @@ -4098,11 +4172,13 @@ before making changes to your Turtle Blocks program')) def load_start(self, ta_file=None): ''' Start a new project with a 'start' brick ''' if ta_file is None: - self.process_data([[0, "start", PALETTE_WIDTH + 20, - self.toolbar_offset + PALETTE_HEIGHT + 20, - [None, None]]]) + self.process_data( + [[0, 'start', PALETTE_WIDTH + 20, + self.toolbar_offset + PALETTE_HEIGHT + 20 + ICON_SIZE, + [None, None]]]) else: self.process_data(data_from_file(ta_file)) + self._loaded_project = ta_file def save_file(self, file_name=None): ''' Start a project to a file ''' @@ -4167,8 +4243,7 @@ before making changes to your Turtle Blocks program')) if not save_project: sx += 20 sy += 20 - data.append((blk.id, name, sx - self.canvas.cx, - sy - self.canvas.cy, connections)) + data.append((blk.id, name, sx, sy, connections)) if save_turtle: for turtle in iter(self.turtles.dict): # Don't save remote turtles @@ -4176,44 +4251,51 @@ before making changes to your Turtle Blocks program')) # Save default turtle as 'Yertle' if turtle == self.nick: turtle = DEFAULT_TURTLE + pos = self.turtles.get_active_turtle().get_xy() data.append( (-1, ['turtle', turtle], - self.canvas.xcor, self.canvas.ycor, - self.canvas.heading, self.canvas.color, - self.canvas.shade, self.canvas.pensize)) + pos[0], pos[1], + self.turtles.get_active_turtle().get_heading(), + self.turtles.get_active_turtle().get_color(), + self.turtles.get_active_turtle().get_shade(), + self.turtles.get_active_turtle().get_pen_size())) return data def display_coordinates(self, clear=False): ''' Display the coordinates of the current turtle on the toolbar ''' if clear: - if self.running_sugar: - self.activity.coordinates_label.set_text('') - self.activity.coordinates_label.show() - elif self.interactive_mode: - self.parent.set_title('') + self._set_coordinates_label('') else: - x = round_int(float(self.canvas.xcor) / self.coord_scale) - y = round_int(float(self.canvas.ycor) / self.coord_scale) - h = round_int(self.canvas.heading) + x = round_int(float(self.turtles.get_active_turtle().get_xy()[0]) / + self.coord_scale) + y = round_int(float(self.turtles.get_active_turtle().get_xy()[1]) / + self.coord_scale) + h = round_int(self.turtles.get_active_turtle().get_heading()) if self.running_sugar: if int(x) == x and int(y) == y and int(h) == h: formatting = '(%d, %d) %d' else: formatting = '(%0.2f, %0.2f) %0.2f' - self.activity.coordinates_label.set_text( - formatting % (x, y, h)) - self.activity.coordinates_label.show() + self._set_coordinates_label(formatting % (x, y, h)) elif self.interactive_mode: if int(x) == x and int(y) == y and int(h) == h: formatting = '%s — %s: %d %s: %d %s: %d' else: formatting = '%s — %s: %0.2f %s: %0.2f %s: %0.2f' - self.parent.set_title( + self._set_coordinates_label( formatting % (self.activity.name, _('xcor'), x, _('ycor'), y, _('heading'), h)) self.update_counter = 0 + def _set_coordinates_label(self, text): + if self.running_sugar: + self.activity.coordinates_label.set_text(text) + self.activity.coordinates_label.show() + elif self.interactive_mode: + self.parent.set_title(text) + + def showlabel(self, shp, label=''): ''' Display a message on a status block ''' if not self.interactive_mode: @@ -4278,16 +4360,17 @@ before making changes to your Turtle Blocks program')) save_picture(self.canvas, image_file) return ta_file, image_file - def save_as_image(self, name="", svg=False): + def save_as_image(self, name='', svg=False): ''' Grab the current canvas and save it. ''' if svg: suffix = '.svg' else: suffix = '.png' - if not self.interactive_mode: + if not self.interactive_mode: # png only save_picture(self.canvas, name[:-3] + suffix) return + if self.running_sugar: if len(name) == 0: filename = 'turtleblocks' + suffix @@ -4304,6 +4387,7 @@ before making changes to your Turtle Blocks program')) else: datapath = os.getcwd() filename = name + suffix + if filename is None: return @@ -4311,6 +4395,7 @@ before making changes to your Turtle Blocks program')) if svg: if self.canvas.cr_svg is None: return + self.canvas.svg_close() self.canvas.svg_reset() else: save_picture(self.canvas, file_path) @@ -4321,14 +4406,14 @@ before making changes to your Turtle Blocks program')) dsobject = datastore.create() if len(name) == 0: - dsobject.metadata['title'] = "%s %s" % \ - (self.activity.metadata['title'], _("image")) + dsobject.metadata['title'] = '%s %s' % \ + (self.activity.metadata['title'], _('image')) else: dsobject.metadata['title'] = name dsobject.metadata['icon-color'] = profile.get_color().to_string() if svg: dsobject.metadata['mime_type'] = 'image/svg+xml' - dsobject.set_file_path(os.path.join(datapath, 'output.svg')) + dsobject.set_file_path(TMP_SVG_PATH) else: dsobject.metadata['mime_type'] = 'image/png' dsobject.set_file_path(file_path) @@ -4336,14 +4421,13 @@ before making changes to your Turtle Blocks program')) dsobject.destroy() self.saved_pictures.append((dsobject.object_id, svg)) if svg: - os.remove(os.path.join(datapath, 'output.svg')) + os.remove(TMP_SVG_PATH) else: os.remove(file_path) else: if svg: subprocess.check_output( - ['mv', os.path.join(datapath, 'output.svg'), - os.path.join(datapath, filename)]) + ['cp', TMP_SVG_PATH, os.path.join(datapath, filename)]) self.saved_pictures.append((file_path, svg)) def just_blocks(self): @@ -4444,6 +4528,8 @@ before making changes to your Turtle Blocks program')) def _find_proto_name(self, name, label, palette='blocks'): ''' Look for a protoblock with this name ''' + if not self.interactive_mode: + return False if isinstance(name, unicode): name = name.encode('ascii', 'replace') if isinstance(label, unicode): @@ -4466,6 +4552,8 @@ before making changes to your Turtle Blocks program')) def _new_stack_block(self, name): ''' Add a stack block to the 'blocks' palette ''' + if not self.interactive_mode: + return if isinstance(name, (float, int)): return if isinstance(name, unicode): @@ -4493,6 +4581,8 @@ before making changes to your Turtle Blocks program')) def _new_box_block(self, name): ''' Add a box block to the 'blocks' palette ''' + if not self.interactive_mode: + return if isinstance(name, (float, int)): return if isinstance(name, unicode): @@ -4521,6 +4611,8 @@ before making changes to your Turtle Blocks program')) def _new_storein_block(self, name): ''' Add a storin block to the 'blocks' palette ''' + if not self.interactive_mode: + return if isinstance(name, (float, int)): return if isinstance(name, unicode): @@ -4557,7 +4649,7 @@ variable')) x = int(x) if 'stack3' + str(x) not in self.lc.stacks or \ self.lc.stacks['stack3' + str(x)] is None: - raise logoerror("#nostack") + raise logoerror('#nostack') self.lc.icall(self.lc.evline, self.lc.stacks['stack3' + str(x)][:]) yield True @@ -4573,10 +4665,10 @@ variable')) try: return self.lc.boxes['box3' + str(x)] except KeyError: - raise logoerror("#emptybox") + raise logoerror('#emptybox') def _prim_setbox(self, name, x, val): - """ Define value of named box """ + ''' Define value of named box ''' if x is not None: if isinstance(convert(x, float, False), float): if int(float(x)) == x: |