Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TurtleArt/tawindow.py
diff options
context:
space:
mode:
Diffstat (limited to 'TurtleArt/tawindow.py')
-rw-r--r--TurtleArt/tawindow.py1140
1 files changed, 631 insertions, 509 deletions
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index ad830d9..64a32fd 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
#Copyright (c) 2007, Playful Invention Company
-#Copyright (c) 2008-10, Walter Bender
-#Copyright (c) 2009-10 Raúl Gutiérrez Segalés
-#Copyright (C) 2010 Emiliano Pastorino <epastorino@plan.ceibal.edu.uy>
+#Copyright (c) 2008-11, Walter Bender
+#Copyright (c) 2009-11 Raúl Gutiérrez Segalés
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
#Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -27,7 +26,15 @@ import pygtk
pygtk.require('2.0')
import gtk
import gobject
-import gst
+from gettext import gettext as _
+
+try:
+ import gst
+ GST_AVAILABLE = True
+except ImportError:
+ # Turtle Art should not fail if gst is not available
+ GST_AVAILABLE = False
+
import os
import os.path
import dbus
@@ -36,7 +43,6 @@ from math import atan2, pi
DEGTOR = 2 * pi / 360
import locale
-from gettext import gettext as _
try:
from sugar.datastore import datastore
@@ -45,84 +51,74 @@ except ImportError:
pass
from taconstants import HORIZONTAL_PALETTE, VERTICAL_PALETTE, BLOCK_SCALE, \
- PALETTE_NAMES, TITLEXY, MEDIA_SHAPES, STATUS_SHAPES, \
- OVERLAY_SHAPES, TOOLBAR_SHAPES, TAB_LAYER, RETURN, \
- OVERLAY_LAYER, CATEGORY_LAYER, BLOCKS_WITH_SKIN, \
- ICON_SIZE, PALETTES, PALETTE_SCALE, BOX_STYLE_MEDIA, \
- PALETTE_WIDTH, MACROS, TOP_LAYER, BLOCK_LAYER, \
- CONTENT_BLOCKS, DEFAULTS, SPECIAL_NAMES, \
- HELP_STRINGS, CURSOR, EXPANDABLE, COLLAPSIBLE, \
- DEAD_DICTS, DEAD_KEYS, TEMPLATES, PYTHON_SKIN, \
- PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK, OLD_NAMES, \
- BOOLEAN_STYLE, BLOCK_NAMES, DEFAULT_TURTLE, \
- TURTLE_LAYER, EXPANDABLE_BLOCKS, COMPARE_STYLE, \
- BOOLEAN_STYLE, EXPANDABLE_ARGS, NUMBER_STYLE, \
- NUMBER_STYLE_PORCH, NUMBER_STYLE_BLOCK, \
- NUMBER_STYLE_VAR_ARG, CONSTANTS, XO1, XO15, UNKNOWN, \
- BASIC_STYLE_VAR_ARG
-from talogo import LogoCode, stop_logo
+ MEDIA_SHAPES, STATUS_SHAPES, OVERLAY_SHAPES, STRING_OR_NUMBER_ARGS, \
+ TOOLBAR_SHAPES, TAB_LAYER, RETURN, OVERLAY_LAYER, CATEGORY_LAYER, \
+ BLOCKS_WITH_SKIN, ICON_SIZE, PALETTE_SCALE, PALETTE_WIDTH, \
+ MACROS, TOP_LAYER, BLOCK_LAYER, OLD_NAMES, DEFAULT_TURTLE, TURTLE_LAYER, \
+ CURSOR, EXPANDABLE, COLLAPSIBLE, DEAD_DICTS, DEAD_KEYS, \
+ TEMPLATES, PYTHON_SKIN, PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK, \
+ EXPANDABLE_ARGS, XO1, XO15, UNKNOWN, TITLEXY, CONTENT_ARGS, CONSTANTS
+from tapalette import palette_names, palette_blocks, expandable_blocks, \
+ block_names, content_blocks, default_values, special_names, block_styles, \
+ help_strings
+from talogo import LogoCode
from tacanvas import TurtleGraphics
from tablock import Blocks, Block
from taturtle import Turtles, Turtle
from tautils import magnitude, get_load_name, get_save_name, data_from_file, \
- data_to_file, round_int, get_id, get_pixbuf_from_journal, \
- movie_media_type, audio_media_type, image_media_type, \
- save_picture, save_svg, calc_image_size, get_path, \
- reset_stack_arm, grow_stack_arm, find_sandwich_top, \
- find_sandwich_bottom, restore_stack, collapse_stack, \
- collapsed, collapsible, hide_button_hit, show_button_hit, \
- arithmetic_check, xy, find_block_to_run, find_top_block, \
- find_start_stack, find_group, find_blk_below, \
- dock_dx_dy, data_to_string, journal_check, chooser, \
- get_hardware
+ data_to_file, round_int, get_id, get_pixbuf_from_journal, \
+ movie_media_type, audio_media_type, image_media_type, save_picture, \
+ save_svg, calc_image_size, get_path, reset_stack_arm, grow_stack_arm, \
+ find_sandwich_top, find_sandwich_bottom, restore_stack, collapse_stack, \
+ collapsed, collapsible, hide_button_hit, show_button_hit, chooser, \
+ arithmetic_check, xy, find_block_to_run, find_top_block, journal_check, \
+ find_group, find_blk_below, data_to_string, find_start_stack, \
+ get_hardware, debug_output, error_output
from tasprite_factory import SVG, svg_str_to_pixbuf, svg_from_file
-from tagplay import stop_media
from sprites import Sprites, Sprite
-from audiograb import AudioGrab_Unknown, AudioGrab_XO1, AudioGrab_XO15
-from rfidutils import strhex2bin, strbin2dec, find_device
from dbus.mainloop.glib import DBusGMainLoop
-HAL_SERVICE = 'org.freedesktop.Hal'
-HAL_MGR_PATH = '/org/freedesktop/Hal/Manager'
-HAL_MGR_IFACE = 'org.freedesktop.Hal.Manager'
-HAL_DEV_IFACE = 'org.freedesktop.Hal.Device'
-REGEXP_SERUSB = '\/org\/freedesktop\/Hal\/devices\/usb_device['\
- 'a-z,A-Z,0-9,_]*serial_usb_[0-9]'
-
-import logging
-_logger = logging.getLogger('turtleart-activity')
+if GST_AVAILABLE:
+ from tagplay import stop_media
class TurtleArtWindow():
""" TurtleArt Window class abstraction """
timeout_tag = [0]
+ _PLUGIN_SUBPATH = 'plugins'
def __init__(self, win, path, parent=None, mycolors=None, mynick=None):
self._loaded_project = ''
- self.win = None
self._sharing = False
self.parent = parent
- self.send_event = None # method to send events over the network
+ self.send_event = None # method to send events over the network
+ self.gst_available = GST_AVAILABLE
if type(win) == gtk.DrawingArea:
self.interactive_mode = True
self.window = win
self.window.set_flags(gtk.CAN_FOCUS)
+ self.window.show_all()
if self.parent is not None:
self.parent.show_all()
self.running_sugar = True
else:
- self.window.show_all()
self.running_sugar = False
self.area = self.window.window
- self.gc = self.area.new_gc()
+ if self.area is not None:
+ self.gc = self.area.new_gc()
+ else:
+ # We lose...
+ debug_output('drawable area is None... punting')
+ exit()
self._setup_events()
elif type(win) == gtk.gdk.Pixmap:
self.interactive_mode = False
self.window = win
self.running_sugar = False
- self.gc = self.window.new_gc()
+ if self.window is not None:
+ self.gc = self.window.new_gc()
else:
- _logger.debug("bad win type %s" % (type(win)))
+ debug_output("bad win type %s" % (type(win)), False)
if self.running_sugar:
self.activity = parent
@@ -147,7 +143,10 @@ class TurtleArtWindow():
self.mouse_x = 0
self.mouse_y = 0
- locale.setlocale(locale.LC_NUMERIC, '')
+ try:
+ locale.setlocale(locale.LC_NUMERIC, '')
+ except locale.Error:
+ debug_output('unsupported locale', self.running_sugar)
self.decimal_point = locale.localeconv()['decimal_point']
if self.decimal_point == '' or self.decimal_point is None:
self.decimal_point = '.'
@@ -155,7 +154,6 @@ class TurtleArtWindow():
self.orientation = HORIZONTAL_PALETTE
self.hw = get_hardware()
- _logger.debug('running on %s hardware' % (self.hw))
if self.hw in (XO1, XO15):
self.lead = 1.0
self.scale = 0.67
@@ -163,14 +161,14 @@ class TurtleArtWindow():
self.color_mode = '565'
else:
self.color_mode = '888'
- if self.running_sugar and not self.activity.new_sugar_system:
+ if self.running_sugar and not self.activity.has_toolbarbox:
self.orientation = VERTICAL_PALETTE
else:
self.lead = 1.0
self.scale = 1.0
self.color_mode = '888' # TODO: Read visual mode from gtk image
- self.block_scale = BLOCK_SCALE
+ self.block_scale = BLOCK_SCALE[3]
self.trash_scale = 0.5
self.myblock = {}
self.python_code = None
@@ -187,6 +185,7 @@ class TurtleArtWindow():
self.media_shapes = {}
self.cartesian = False
self.polar = False
+ self.metric = False
self.overlay_shapes = {}
self.toolbar_shapes = {}
self.toolbar_offset = 0
@@ -196,7 +195,6 @@ class TurtleArtWindow():
self.palette_sprs = []
self.palettes = []
self.palette_button = []
- self.trash_index = PALETTE_NAMES.index('trash')
self.trash_stack = []
self.selected_palette = None
self.previous_palette = None
@@ -219,10 +217,10 @@ class TurtleArtWindow():
self.sprite_list = None
self.turtles = Turtles(self.sprite_list)
- if mynick is None:
+ if self.nick is None:
self.default_turtle_name = DEFAULT_TURTLE
else:
- self.default_turtle_name = mynick
+ self.default_turtle_name = self.nick
if mycolors is None:
Turtle(self.turtles, self.default_turtle_name)
else:
@@ -252,99 +250,100 @@ class TurtleArtWindow():
CONSTANTS['width'] = int(self.canvas.width / self.coord_scale)
CONSTANTS['height'] = int(self.canvas.height / self.coord_scale)
- if self.interactive_mode:
- self._setup_misc()
- self._show_toolbar_palette(0, False)
-
- # setup sound/sensor grab
- if self.hw in [XO1, XO15]:
- PALETTES[PALETTE_NAMES.index('sensor')].append('resistance')
- PALETTES[PALETTE_NAMES.index('sensor')].append('voltage')
- self.audio_started = False
-
- self.camera_available = False
- v4l2src = gst.element_factory_make('v4l2src')
- if v4l2src.props.device_name is not None:
- PALETTES[PALETTE_NAMES.index('sensor')].append('readcamera')
- PALETTES[PALETTE_NAMES.index('sensor')].append('luminance')
- PALETTES[PALETTE_NAMES.index('sensor')].append('camera')
- self.camera_available = True
+ self._icon_paths = [os.path.join(self.path, 'icons')]
+ self._plugins = []
+ self._init_plugins()
self.lc = LogoCode(self)
- self.saved_pictures = []
-
- self.block_operation = ''
- """
- The following code will initialize a USB RFID reader. Please note that
- in order to make this initialization function work, it is necessary to
- set the permission for the ttyUSB device to 0666. You can do this by
- adding a rule to /etc/udev/rules.d
-
- As root (using sudo or su), copy the following text into a new file in
- /etc/udev/rules.d/94-ttyUSB-rules
-
- KERNEL=="ttyUSB[0-9]",MODE="0666"
-
- You only have to do this once.
- """
-
- self.rfid_connected = False
- self.rfid_device = find_device()
- self.rfid_idn = ''
-
- if self.rfid_device is not None:
- _logger.info("RFID device found")
- self.rfid_connected = self.rfid_device.do_connect()
- if self.rfid_connected:
- self.rfid_device.connect("tag-read", self._tag_read_cb)
- self.rfid_device.connect("disconnected", self._disconnected_cb)
-
- loop = DBusGMainLoop()
- bus = dbus.SystemBus(mainloop=loop)
- hmgr_iface = dbus.Interface(bus.get_object(HAL_SERVICE,
- HAL_MGR_PATH), HAL_MGR_IFACE)
+ from tabasics import Palettes
+ p = Palettes(self)
+ self._setup_plugins()
- hmgr_iface.connect_to_signal('DeviceAdded', self._device_added_cb)
+ if self.interactive_mode:
+ self._setup_misc()
+ self.show_toolbar_palette(0, False)
- PALETTES[PALETTE_NAMES.index('sensor')].append('rfid')
+ self.saved_pictures = []
+ self.block_operation = ''
- def _device_added_cb(self, path):
- """
- Called from hal connection when a new device is plugged.
- """
- if not self.rfid_connected:
- self.rfid_device = find_device()
- _logger.debug("DEVICE_ADDED: %s"%self.rfid_device)
- if self.rfid_device is not None:
- _logger.debug("DEVICE_ADDED: RFID device is not None!")
- self.rfid_connected = self._device.do_connect()
- if self.rfid_connected:
- _logger.debug("DEVICE_ADDED: Connected!")
- self.rfid_device.connect("tag-read", self._tag_read_cb)
- self.rfid_device.connect("disconnected", self._disconnected_cb)
-
- def _disconnected_cb(self, device, text):
- """
- Called when the device is disconnected.
- """
- self.rfid_connected = False
- self.rfid_device = None
+ def _get_plugin_home(self):
+ """ Look in the execution directory """
+ path = os.path.join(self.path, self._PLUGIN_SUBPATH)
+ if os.path.exists(path):
+ return path
+ else:
+ return None
- def _tag_read_cb(self, device, tagid):
- """
- Callback for "tag-read" signal. Receives the read tag id.
- """
- idbin = strhex2bin(tagid)
- self.rfid_idn = strbin2dec(idbin[26:64])
- while self.rfid_idn.__len__() < 9:
- self.rfid_idn = '0' + self.rfid_idn
- print tagid, idbin, self.rfid_idn
-
- def new_buffer(self, buf):
- """ Append a new buffer to the ringbuffer """
- self.lc.ringbuffer.append(buf)
- return True
+ def _get_plugins_from_plugins_dir(self, path):
+ """ Look for plugin files in plugin dir. """
+ plugin_files = []
+ if path is not None:
+ candidates = os.listdir(path)
+ for dirname in candidates:
+ if os.path.exists(
+ os.path.join(path, dirname, dirname + '.py')):
+ plugin_files.append(dirname)
+ return plugin_files
+
+ def _init_plugins(self):
+ """ Try importing plugin files from the plugin dir. """
+ for plugin_dir in self._get_plugins_from_plugins_dir(
+ self._get_plugin_home()):
+ plugin_class = plugin_dir.capitalize()
+ f = "def f(self): from plugins.%s.%s import %s; return %s(self)" \
+ % (plugin_dir, plugin_dir, plugin_class, plugin_class)
+ plugins = {}
+ try:
+ exec f in globals(), plugins
+ self._plugins.append(plugins.values()[0](self))
+ # debug_output('successfully importing %s' % (plugin_class))
+ except ImportError:
+ debug_output('failed to import %s' % (plugin_class))
+
+ # Add the icon dir for each plugin to the icon_theme search path
+ for plugin_dir in self._get_plugins_from_plugins_dir(
+ self._get_plugin_home()):
+ self._add_plugin_icon_dir(os.path.join(self._get_plugin_home(),
+ plugin_dir))
+
+ def _add_plugin_icon_dir(self, dirname):
+ ''' If there is an icon subdir, add it to the search path. '''
+ icon_theme = gtk.icon_theme_get_default()
+ icon_path = os.path.join(dirname, 'icons')
+ if os.path.exists(icon_path):
+ icon_theme.append_search_path(icon_path)
+ self._icon_paths.append(icon_path)
+
+ def _setup_plugins(self):
+ """ Initial setup -- call just once. """
+ for plugin in self._plugins:
+ plugin.setup()
+
+ def _start_plugins(self):
+ """ Start is called everytime we execute blocks. """
+ for plugin in self._plugins:
+ plugin.start()
+
+ def _stop_plugins(self):
+ """ Stop is called whenever we stop execution. """
+ for plugin in self._plugins:
+ plugin.stop()
+
+ def background_plugins(self):
+ """ Background is called when we are pushed to the background. """
+ for plugin in self._plugins:
+ plugin.goto_background()
+
+ def foreground_plugins(self):
+ """ Foreground is called when we are return from the background. """
+ for plugin in self._plugins:
+ plugin.return_to_foreground()
+
+ def _quit_plugins(self):
+ """ Quit is called upon program exit. """
+ for plugin in self._plugins:
+ plugin.quit()
def _setup_events(self):
""" Register the events we listen to. """
@@ -361,41 +360,41 @@ class TurtleArtWindow():
def _setup_misc(self):
""" Misc. sprites for status, overlays, etc. """
# media blocks get positioned into other blocks
- for _name in MEDIA_SHAPES:
- if _name[0:7] == 'journal' and not self.running_sugar:
- file_name = 'file' + _name[7:]
+ for name in MEDIA_SHAPES:
+ if name[0:7] == 'journal' and not self.running_sugar:
+ filename = 'file' + name[7:]
else:
- file_name = _name
- self.media_shapes[_name] = svg_str_to_pixbuf(svg_from_file(
- "%s/images/%s.svg" % (self.path, file_name)))
+ filename = name
+ self.media_shapes[name] = svg_str_to_pixbuf(svg_from_file(
+ "%s/images/%s.svg" % (self.path, filename)))
- for i, _name in enumerate(STATUS_SHAPES):
- self.status_shapes[_name] = svg_str_to_pixbuf(svg_from_file(
- "%s/images/%s.svg" % (self.path, _name)))
+ for i, name in enumerate(STATUS_SHAPES):
+ self.status_shapes[name] = svg_str_to_pixbuf(svg_from_file(
+ "%s/images/%s.svg" % (self.path, name)))
self.status_spr = Sprite(self.sprite_list, 0, self.height - 200,
self.status_shapes['status'])
self.status_spr.hide()
self.status_spr.type = 'status'
- for _name in OVERLAY_SHAPES:
- self.overlay_shapes[_name] = Sprite(self.sprite_list,
+ for name in OVERLAY_SHAPES:
+ 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))))
- self.overlay_shapes[_name].hide()
- self.overlay_shapes[_name].type = 'overlay'
+ 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:
offset = self.width - 55 * len(TOOLBAR_SHAPES)
- for i, _name in enumerate(TOOLBAR_SHAPES):
- self.toolbar_shapes[_name] = Sprite(self.sprite_list,
- i * 55 + offset, 0,
- svg_str_to_pixbuf(
- svg_from_file("%s/icons/%s.svg" % (self.path, _name))))
- self.toolbar_shapes[_name].set_layer(TAB_LAYER)
- self.toolbar_shapes[_name].name = _name
- self.toolbar_shapes[_name].type = 'toolbar'
+ for i, name in enumerate(TOOLBAR_SHAPES):
+ self.toolbar_shapes[name] = Sprite(
+ self.sprite_list, i * 55 + offset, 0,
+ svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self.path, 'icons', '%s.svg' % (name)))))
+ self.toolbar_shapes[name].set_layer(TAB_LAYER)
+ self.toolbar_shapes[name].name = name
+ self.toolbar_shapes[name].type = 'toolbar'
self.toolbar_shapes['stopiton'].hide()
def set_sharing(self, shared):
@@ -420,35 +419,17 @@ class TurtleArtWindow():
self.lc.prim_clear()
self.display_coordinates()
- def _start_audiograb(self):
- """ Start grabbing audio if there is an audio block in use """
- if len(self.block_list.get_similar_blocks('block',
- ['volume', 'sound', 'pitch', 'resistance', 'voltage'])) > 0:
- if self.audio_started:
- self.audiograb.resume_grabbing()
- else:
- if self.hw == XO15:
- self.audiograb = AudioGrab_XO15(self.new_buffer, self)
- elif self.hw == XO1:
- self.audiograb = AudioGrab_XO1(self.new_buffer, self)
- else:
- self.audiograb = AudioGrab_Unknown(self.new_buffer, self)
- self.audiograb.start_grabbing()
- self.audio_started = True
-
def run_button(self, time):
""" Run turtle! """
if self.running_sugar:
self.activity.recenter()
- if self.interactive_mode:
- self._start_audiograb()
-
# Look for a 'start' block
for blk in self.just_blocks():
if find_start_stack(blk):
self.step_time = time
- _logger.debug("running stack starting from %s" % (blk.name))
+ debug_output("running stack starting from %s" % (blk.name),
+ self.running_sugar)
self._run_stack(blk)
return
@@ -456,15 +437,15 @@ class TurtleArtWindow():
for blk in self.just_blocks():
if find_block_to_run(blk):
self.step_time = time
- _logger.debug("running stack starting from %s" % (blk.name))
+ debug_output("running stack starting from %s" % (blk.name),
+ self.running_sugar)
self._run_stack(blk)
return
def stop_button(self):
""" Stop button """
- stop_logo(self)
- if self.audio_started:
- self.audiograb.pause_grabbing()
+ self.lc.stop_logo()
+ self._stop_plugins()
def set_userdefined(self, blk=None):
""" Change icon for user-defined blocks after loading Python code. """
@@ -505,28 +486,38 @@ class TurtleArtWindow():
self.overlay_shapes['polar'].hide()
self.polar = False
+ def set_metric(self, flag):
+ """ Turn on/off metric coordinates """
+ if flag:
+ self.overlay_shapes['metric'].set_layer(OVERLAY_LAYER)
+ self.metric = True
+ else:
+ self.overlay_shapes['metric'].hide()
+ self.metric = False
+
def update_overlay_position(self, widget, event):
""" Reposition the overlays when window size changes """
self.width = event.width
self.height = event.height
- for _name in OVERLAY_SHAPES:
- shape = self.overlay_shapes[_name]
+ for name in OVERLAY_SHAPES:
+ shape = self.overlay_shapes[name]
showing = False
if shape in shape._sprites.list:
shape.hide()
showing = True
- self.overlay_shapes[_name] = Sprite(self.sprite_list,
+ 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)
+ self.overlay_shapes[name].set_layer(OVERLAY_LAYER)
else:
- self.overlay_shapes[_name].hide()
- self.overlay_shapes[_name].type = 'overlay'
+ 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()
@@ -543,9 +534,9 @@ class TurtleArtWindow():
if blk.status != 'collapsed':
blk.spr.set_layer(BLOCK_LAYER)
self.show_palette()
- if self.activity is not None and self.activity.new_sugar_system:
+ if self.activity is not None and self.activity.has_toolbarbox:
self.activity.palette_buttons[0].set_icon(
- PALETTE_NAMES[0] + 'on')
+ palette_names[0] + 'on')
self.hide = False
if self.running_sugar:
self.activity.recenter()
@@ -568,10 +559,10 @@ class TurtleArtWindow():
def show_palette(self, n=0):
""" Show palette """
- self._show_toolbar_palette(n)
+ self.show_toolbar_palette(n)
self.palette_button[self.orientation].set_layer(TAB_LAYER)
self.palette_button[2].set_layer(TAB_LAYER)
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
self.toolbar_spr.set_layer(CATEGORY_LAYER)
self.palette = True
@@ -580,7 +571,7 @@ class TurtleArtWindow():
self._hide_toolbar_palette()
self.palette_button[self.orientation].hide()
self.palette_button[2].hide()
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
self.toolbar_spr.hide()
self.palette = False
@@ -591,7 +582,7 @@ class TurtleArtWindow():
self.hide = False
self.hideshow_button()
if self.running_sugar:
- self.activity.do_hide()
+ self.activity.do_hide_blocks()
def showblocks(self):
""" Callback from 'show blocks' block """
@@ -600,7 +591,7 @@ class TurtleArtWindow():
self.hide = True
self.hideshow_button()
if self.running_sugar:
- self.activity.do_show()
+ self.activity.do_show_blocks()
def resize_blocks(self, blocks=None):
""" Resize blocks or if blocks is None, all of the blocks """
@@ -635,65 +626,21 @@ class TurtleArtWindow():
if blk.name in BLOCKS_WITH_SKIN:
self._resize_skin(blk)
- def _show_toolbar_palette(self, n, init_only=False):
+ def show_toolbar_palette(self, n, init_only=False, regenerate=False):
""" Show the toolbar palettes, creating them on init_only """
- if (self.activity is None or not self.activity.new_sugar_system) and\
+ # If we are running the 0.86+ toolbar, the selectors are already
+ # created, as toolbar buttons. Otherwise, we need to create them.
+ if (self.activity is None or not self.activity.has_toolbarbox) and \
self.selectors == []:
- # Create the selectors
- svg = SVG()
- x, y = 50, 0
- for i, name in enumerate(PALETTE_NAMES):
- a = svg_str_to_pixbuf(svg_from_file("%s/icons/%soff.svg" % (
- self.path, name)))
- b = svg_str_to_pixbuf(svg_from_file("%s/icons/%son.svg" % (
- self.path, name)))
- self.selector_shapes.append([a, b])
- self.selectors.append(Sprite(self.sprite_list, x, y, a))
- self.selectors[i].type = 'selector'
- self.selectors[i].name = name
- self.selectors[i].set_layer(TAB_LAYER)
- w = self.selectors[i].get_dimensions()[0]
- x += int(w)
-
- # Create the toolbar background
- self.toolbar_offset = ICON_SIZE
- self.toolbar_spr = Sprite(self.sprite_list, 0, 0,
- svg_str_to_pixbuf(svg.toolbar(self.width, ICON_SIZE)))
- self.toolbar_spr.type = 'toolbar'
- self.toolbar_spr.set_layer(CATEGORY_LAYER)
+ # First, create the selector buttons
+ self._create_the_selectors()
+ # Create the empty palettes that we'll then populate with prototypes.
if self.palette_sprs == []:
- # Create the empty palettes
- if len(self.palettes) == 0:
- for i in range(len(PALETTES)):
- self.palettes.append([])
-
- # Create empty palette backgrounds
- for i in PALETTE_NAMES:
- self.palette_sprs.append([None, None])
-
- # Create the palette orientation button
- self.palette_button.append(Sprite(self.sprite_list, 0,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%s/images/palettehorizontal.svg" % (self.path)))))
- self.palette_button.append(Sprite(self.sprite_list, 0,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%s/images/palettevertical.svg" % (self.path)))))
- self.palette_button[0].name = _('orientation')
- self.palette_button[1].name = _('orientation')
- self.palette_button[0].type = 'palette'
- self.palette_button[1].type = 'palette'
- self.palette_button[self.orientation].set_layer(TAB_LAYER)
- self.palette_button[1 - self.orientation].hide()
-
- # Create the palette next button
- self.palette_button.append(Sprite(self.sprite_list, 16,
- self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
- "%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)
+ self._create_the_empty_palettes()
+ # At initialization of the program, we don't actually populate
+ # the palettes.
if init_only:
return
@@ -703,27 +650,121 @@ class TurtleArtWindow():
self.selected_palette = n
self.previous_palette = self.selected_palette
- if self.activity is None or not self.activity.new_sugar_system:
+ # Make sure all of the selectors are visible. (We don't need to do
+ # this for 0.86+ toolbars since the selectors are toolbar buttons.)
+ if self.activity is None or not self.activity.has_toolbarbox:
self.selected_selector = self.selectors[n]
- # Make sure all of the selectors are visible.
self.selectors[n].set_shape(self.selector_shapes[n][1])
- for i in range(len(PALETTES)):
+ for i in range(len(palette_blocks)):
self.selectors[i].set_layer(TAB_LAYER)
# Show the palette with the current orientation.
if self.palette_sprs[n][self.orientation] is not None:
self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER)
+ # Create 'proto' blocks for each palette entry
+ self._create_proto_blocks(n, regenerate=regenerate)
+
+ self._layout_palette(n, regenerate=regenerate)
+ for blk in self.palettes[n]:
+ blk.spr.set_layer(TAB_LAYER)
+ if n == palette_names.index('trash'):
+ for blk in self.trash_stack:
+ for gblk in find_group(blk):
+ if gblk.status != 'collapsed':
+ gblk.spr.set_layer(TAB_LAYER)
+
+ def _create_the_selectors(self):
+ ''' Create the palette selector buttons. '''
+ svg = SVG()
+ x, y = 50, 0 # positioned at the left, top
+ for i, name in enumerate(palette_names):
+ for path in self._icon_paths:
+ if os.path.exists(os.path.join(path, '%soff.svg' % (name))):
+ icon_pathname = os.path.join(path, '%soff.svg' % (name))
+ break
+ if icon_pathname is not None:
+ off_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
+ else:
+ off_shape = svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self._icon_paths[0], 'extrasoff.svg')))
+ error_output('Unable to open %soff.svg' % (name),
+ self.running_sugar)
+ for path in self._icon_paths:
+ if os.path.exists(os.path.join(path, '%son.svg' % (name))):
+ icon_pathname = os.path.join(path, '%son.svg' % (name))
+ break
+ if icon_pathname is not None:
+ on_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
+ else:
+ on_shape = svg_str_to_pixbuf(svg_from_file(os.path.join(
+ self._icon_paths[0], 'extrason.svg')))
+ error_output('Unable to open %son.svg' % (name),
+ self.running_sugar)
+
+ self.selector_shapes.append([off_shape, on_shape])
+ self.selectors.append(Sprite(self.sprite_list, x, y, off_shape))
+ self.selectors[i].type = 'selector'
+ self.selectors[i].name = name
+ self.selectors[i].set_layer(TAB_LAYER)
+ w = self.selectors[i].get_dimensions()[0]
+ x += int(w) # running from left to right
+
+ # Create the toolbar background for the selectors
+ self.toolbar_offset = ICON_SIZE
+ self.toolbar_spr = Sprite(self.sprite_list, 0, 0,
+ svg_str_to_pixbuf(svg.toolbar(self.width, ICON_SIZE)))
+ self.toolbar_spr.type = 'toolbar'
+ self.toolbar_spr.set_layer(CATEGORY_LAYER)
+
+ def _create_the_empty_palettes(self):
+ ''' Create the empty palettes to be populated by prototype blocks. '''
+ if len(self.palettes) == 0:
+ for i in range(len(palette_blocks)):
+ self.palettes.append([])
+
+ # Create empty palette backgrounds
+ for i in palette_names:
+ self.palette_sprs.append([None, None])
+
+ # Create the palette orientation button
+ self.palette_button.append(Sprite(self.sprite_list, 0,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%s/images/palettehorizontal.svg" % (self.path)))))
+ self.palette_button.append(Sprite(self.sprite_list, 0,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%s/images/palettevertical.svg" % (self.path)))))
+ self.palette_button[0].name = _('orientation')
+ self.palette_button[1].name = _('orientation')
+ self.palette_button[0].type = 'palette'
+ self.palette_button[1].type = 'palette'
+ self.palette_button[self.orientation].set_layer(TAB_LAYER)
+ self.palette_button[1 - self.orientation].hide()
+
+ # Create the palette next button
+ self.palette_button.append(Sprite(self.sprite_list, 16,
+ self.toolbar_offset, svg_str_to_pixbuf(svg_from_file(
+ "%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)
+
+ def _create_proto_blocks(self, n, regenerate=False):
+ ''' Create the protoblocks that will populate a palette. '''
+ if regenerate:
+ for blk in self.palettes[n]:
+ blk.type = 'trash'
+ self.palettes[n] = []
+
if self.palettes[n] == []:
- # Create 'proto' blocks for each palette entry
- for i, name in enumerate(PALETTES[n]):
+ for i, name in enumerate(palette_blocks[n]):
self.palettes[n].append(Block(self.block_list,
self.sprite_list, name, 0, 0, 'proto', [], PALETTE_SCALE))
self.palettes[n][i].spr.set_layer(TAB_LAYER)
self.palettes[n][i].unhighlight()
# Some proto blocks get a skin.
- if name in BOX_STYLE_MEDIA:
+ if name in block_styles['box-style-media']:
self._proto_skin(name + 'small', n, i)
elif name[:8] == 'template':
self._proto_skin(name[8:], n, i)
@@ -732,25 +773,16 @@ class TurtleArtWindow():
elif name in PYTHON_SKIN:
self._proto_skin('pythonsmall', n, i)
- self._layout_palette(n)
- for blk in self.palettes[n]:
- blk.spr.set_layer(TAB_LAYER)
- if n == self.trash_index:
- for blk in self.trash_stack:
- for gblk in find_group(blk):
- if gblk.status != 'collapsed':
- gblk.spr.set_layer(TAB_LAYER)
-
def _hide_toolbar_palette(self):
""" Hide the toolbar palettes """
self._hide_previous_palette()
- if self.activity is None or not self.activity.new_sugar_system:
+ if self.activity is None or not self.activity.has_toolbarbox:
# Hide the selectors
- for i in range(len(PALETTES)):
+ for i in range(len(palette_blocks)):
self.selectors[i].hide()
elif self.selected_palette is not None:
self.activity.palette_buttons[self.selected_palette].set_icon(
- PALETTE_NAMES[self.selected_palette] + 'off')
+ palette_names[self.selected_palette] + 'off')
self.selected_palette = None
self.previous_palette = None
@@ -758,119 +790,117 @@ class TurtleArtWindow():
""" Hide just the previously viewed toolbar palette """
# Hide previous palette
if self.previous_palette is not None:
- for i in range(len(PALETTES[self.previous_palette])):
- self.palettes[self.previous_palette][i].spr.hide()
- self.palette_sprs[self.previous_palette][
- self.orientation].hide()
- if self.activity is None or not self.activity.new_sugar_system:
+ for proto in self.palettes[self.previous_palette]:
+ proto.spr.hide()
+ self.palette_sprs[self.previous_palette][self.orientation].hide()
+ if self.activity is None or not self.activity.has_toolbarbox:
self.selectors[self.previous_palette].set_shape(
self.selector_shapes[self.previous_palette][0])
elif self.previous_palette is not None and \
self.previous_palette != self.selected_palette:
self.activity.palette_buttons[self.previous_palette].set_icon(
- PALETTE_NAMES[self.previous_palette] + 'off')
- if self.previous_palette == self.trash_index:
+ palette_names[self.previous_palette] + 'off')
+ if self.previous_palette == palette_names.index('trash'):
for blk in self.trash_stack:
for gblk in find_group(blk):
gblk.spr.hide()
def _horizontal_layout(self, x, y, blocks):
""" Position prototypes in a horizontal palette. """
- _max_w = 0
+ max_w = 0
for blk in blocks:
- _w, _h = self._width_and_height(blk)
- if y + _h > PALETTE_HEIGHT + self.toolbar_offset:
- x += int(_max_w + 3)
+ w, h = self._width_and_height(blk)
+ if y + h > PALETTE_HEIGHT + self.toolbar_offset:
+ x += int(max_w + 3)
y = self.toolbar_offset + 3
- _max_w = 0
- (_bx, _by) = blk.spr.get_xy()
- _dx = x - _bx
- _dy = y - _by
+ max_w = 0
+ (bx, by) = blk.spr.get_xy()
+ dx = x - bx
+ dy = y - by
for g in find_group(blk):
- g.spr.move_relative((int(_dx), int(_dy)))
- y += int(_h + 3)
- if _w > _max_w:
- _max_w = _w
- return x, y, _max_w
+ g.spr.move_relative((int(dx), int(dy)))
+ y += int(h + 3)
+ if w > max_w:
+ max_w = w
+ return x, y, max_w
def _vertical_layout(self, x, y, blocks):
""" Position prototypes in a vertical palette. """
- _row = []
- _row_w = 0
- _max_h = 0
- for _b in blocks:
- _w, _h = self._width_and_height(_b)
- if x + _w > PALETTE_WIDTH:
+ row = []
+ row_w = 0
+ max_h = 0
+ for b in blocks:
+ w, h = self._width_and_height(b)
+ if x + w > PALETTE_WIDTH:
# Recenter row.
- _dx = int((PALETTE_WIDTH - _row_w) / 2)
- for _r in _row:
- for _g in find_group(_r):
- _g.spr.move_relative((_dx, 0))
- _row = []
- _row_w = 0
+ dx = int((PALETTE_WIDTH - row_w) / 2)
+ for r in row:
+ for g in find_group(r):
+ g.spr.move_relative((dx, 0))
+ row = []
+ row_w = 0
x = 4
- y += int(_max_h + 3)
- _max_h = 0
- _row.append(_b)
- _row_w += (4 + _w)
- (_bx, _by) = _b.spr.get_xy()
- _dx = int(x - _bx)
- _dy = int(y - _by)
- for _g in find_group(_b):
- _g.spr.move_relative((_dx, _dy))
- x += int(_w + 4)
- if _h > _max_h:
- _max_h = _h
+ y += int(max_h + 3)
+ max_h = 0
+ row.append(b)
+ row_w += (4 + w)
+ (bx, by) = b.spr.get_xy()
+ dx = int(x - bx)
+ dy = int(y - by)
+ for g in find_group(b):
+ g.spr.move_relative((dx, dy))
+ x += int(w + 4)
+ if h > max_h:
+ max_h = h
# Recenter last row.
- _dx = int((PALETTE_WIDTH - _row_w) / 2)
- for _r in _row:
- for _g in find_group(_r):
- _g.spr.move_relative((_dx, 0))
- return x, y, _max_h
+ dx = int((PALETTE_WIDTH - row_w) / 2)
+ for r in row:
+ for g in find_group(r):
+ g.spr.move_relative((dx, 0))
+ return x, y, max_h
- def _layout_palette(self, n):
+ def _layout_palette(self, n, regenerate=False):
""" Layout prototypes in a palette. """
if n is not None:
if self.orientation == HORIZONTAL_PALETTE:
- _x, _y = 20, self.toolbar_offset + 5
- _x, _y, _max = self._horizontal_layout(_x, _y,
- self.palettes[n])
- if n == self.trash_index:
- _x, _y, _max = self._horizontal_layout(_x + _max, _y,
- self.trash_stack)
- _w = _x + _max + 25
- if self.palette_sprs[n][self.orientation] is None:
- svg = SVG()
- self.palette_sprs[n][self.orientation] = Sprite(
- self.sprite_list, 0, self.toolbar_offset,
- svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT)))
- self.palette_sprs[n][self.orientation].type = 'category'
- if n == PALETTE_NAMES.index('trash'):
- svg = SVG()
- self.palette_sprs[n][self.orientation].set_shape(
- svg_str_to_pixbuf(svg.palette(_w, PALETTE_HEIGHT)))
- self.palette_button[2].move((_w - 20, self.toolbar_offset))
+ x, y = 20, self.toolbar_offset + 5
+ x, y, max_w = self._horizontal_layout(x, y, self.palettes[n])
+ if n == palette_names.index('trash'):
+ x, y, max_w = self._horizontal_layout(x + max_w, y,
+ self.trash_stack)
+ w = x + max_w + 25
+ self._make_palette_spr(n, 0, self.toolbar_offset,
+ w, PALETTE_HEIGHT, regenerate)
+ self.palette_button[2].move((w - 20, self.toolbar_offset))
else:
- _x, _y = 5, self.toolbar_offset + 15
- _x, _y, _max = self._vertical_layout(_x, _y, self.palettes[n])
- if n == PALETTE_NAMES.index('trash'):
- _x, _y, _max = self._vertical_layout(_x, _y + _max,
- self.trash_stack)
- _h = _y + _max + 25 - self.toolbar_offset
- if self.palette_sprs[n][self.orientation] is None:
- svg = SVG()
- self.palette_sprs[n][self.orientation] = \
- Sprite(self.sprite_list, 0, self.toolbar_offset,
- svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h)))
- self.palette_sprs[n][self.orientation].type = 'category'
- if n == PALETTE_NAMES.index('trash'):
- svg = SVG()
- self.palette_sprs[n][self.orientation].set_shape(
- svg_str_to_pixbuf(svg.palette(PALETTE_WIDTH, _h)))
+ x, y = 5, self.toolbar_offset + 15
+ x, y, max_h = self._vertical_layout(x, y, self.palettes[n])
+ if n == palette_names.index('trash'):
+ x, y, max_h = self._vertical_layout(x, y + max_h,
+ self.trash_stack)
+ h = y + max_h + 25 - self.toolbar_offset
+ self._make_palette_spr(n, 0, self.toolbar_offset,
+ PALETTE_WIDTH, h, regenerate)
self.palette_button[2].move((PALETTE_WIDTH - 20,
self.toolbar_offset))
self.palette_sprs[n][self.orientation].set_layer(CATEGORY_LAYER)
+ def _make_palette_spr(self, n, x, y, w, h, regenerate=False):
+ ''' Make the background for the palette. '''
+ if regenerate and not self.palette_sprs[n][self.orientation] is None:
+ self.palette_sprs[n][self.orientation].hide()
+ self.palette_sprs[n][self.orientation] = None
+ if self.palette_sprs[n][self.orientation] is None:
+ svg = SVG()
+ self.palette_sprs[n][self.orientation] = \
+ Sprite(self.sprite_list, x, y, svg_str_to_pixbuf(
+ svg.palette(w, h)))
+ self.palette_sprs[n][self.orientation].type = 'category'
+ if n == palette_names.index('trash'):
+ svg = SVG()
+ self.palette_sprs[n][self.orientation].set_shape(
+ svg_str_to_pixbuf(svg.palette(w, h)))
+
def _buttonpress_cb(self, win, event):
""" Button press """
self.window.grab_focus()
@@ -916,6 +946,10 @@ class TurtleArtWindow():
self._restore_latest_from_trash()
elif blk.name == 'empty':
self._empty_trash()
+ elif blk.name == 'trashall':
+ for b in self.just_blocks():
+ if b.type != 'trash':
+ self._put_in_trash(find_top_block(b))
elif blk.name in MACROS:
self._new_macro(blk.name, x + 20, y + 20)
else:
@@ -925,7 +959,7 @@ class TurtleArtWindow():
'block', blk.name)) > 0:
self.showlabel('dupstack')
return True
- # You cannot miz and match sensor blocks
+ # You cannot mix and match sensor blocks
elif blk.name in ['sound', 'volume', 'pitch']:
if len(self.block_list.get_similar_blocks(
'block', ['resistance', 'voltage'])) > 0:
@@ -954,6 +988,9 @@ class TurtleArtWindow():
# Next, look for a turtle
t = self.turtles.spr_to_turtle(spr)
if t is not None:
+ # If turtle is shared, ignore click
+ if self.remote_turtle(t.get_name()):
+ return True
self.selected_turtle = t
self.canvas.set_turtle(self.turtles.get_turtle_key(t))
self._turtle_pressed(x, y)
@@ -972,18 +1009,18 @@ class TurtleArtWindow():
elif spr.type == 'palette':
if spr.name == _('next'):
i = self.selected_palette + 1
- if i == len(PALETTE_NAMES):
+ if i == len(palette_names):
i = 0
if self.activity is None or \
- not self.activity.new_sugar_system:
+ not self.activity.has_toolbarbox:
self._select_category(self.selectors[i])
else:
if self.selected_palette is not None:
self.activity.palette_buttons[
self.selected_palette].set_icon(
- PALETTE_NAMES[self.selected_palette] + 'off')
+ palette_names[self.selected_palette] + 'off')
self.activity.palette_buttons[i].set_icon(
- PALETTE_NAMES[i] + 'on')
+ palette_names[i] + 'on')
self.show_palette(i)
else:
self.orientation = 1 - self.orientation
@@ -1018,7 +1055,7 @@ class TurtleArtWindow():
self.lc.trace = 0
self.run_button(0)
elif spr.name == 'run-slowoff':
- self.lc.trace = 0
+ self.lc.trace = 1
self.run_button(3)
elif spr.name == 'debugoff':
self.lc.trace = 1
@@ -1060,8 +1097,8 @@ class TurtleArtWindow():
if gblk.name in BLOCKS_WITH_SKIN:
self._resize_skin(gblk)
- # self.show_palette(self.trash_index)
- if self.selected_palette != self.trash_index:
+ # self.show_palette(palette_names.index('trash'))
+ if self.selected_palette != palette_names.index('trash'):
for gblk in group:
gblk.spr.hide()
@@ -1113,8 +1150,8 @@ class TurtleArtWindow():
def _in_the_trash(self, x, y):
""" Is x, y over the trash can? """
"""
- if self.selected_palette == self.trash_index and \
- self.palette_sprs[self.trash_index][self.orientation].hit((x, y)):
+ if self.selected_palette == palette_names.index('trash') and \
+ self.palette_sprs[palette_names.index('trash')][self.orientation].hit((x, y)):
return True
"""
if self.selected_palette is not None and \
@@ -1146,14 +1183,18 @@ class TurtleArtWindow():
self.selected_blk.unhighlight()
self.selected_blk = None
- def _new_block(self, name, x, y):
+ def _new_block(self, name, x, y, defaults=None):
""" Make a new block. """
- if name in CONTENT_BLOCKS:
- newblk = Block(self.block_list, self.sprite_list, name, x - 20,
- y - 20, 'block', DEFAULTS[name], self.block_scale)
+ x_pos = x - 20
+ y_pos = y - 20
+ if name in content_blocks:
+ if defaults == None:
+ defaults = default_values[name]
+ newblk = Block(self.block_list, self.sprite_list, name, x_pos,
+ y_pos, 'block', defaults, self.block_scale)
else:
- newblk = Block(self.block_list, self.sprite_list, name, x - 20,
- y - 20, 'block', [], self.block_scale)
+ newblk = Block(self.block_list, self.sprite_list, name, x_pos,
+ y_pos, 'block', [], self.block_scale)
# Add a 'skin' to some blocks
if name in PYTHON_SKIN:
@@ -1161,15 +1202,17 @@ class TurtleArtWindow():
self._block_skin('pythonon', newblk)
else:
self._block_skin('pythonoff', newblk)
- elif name in BOX_STYLE_MEDIA:
+ elif name in block_styles['box-style-media']:
self._block_skin(name + 'off', newblk)
newspr = newblk.spr
newspr.set_layer(TOP_LAYER)
self.drag_pos = 20, 20
newblk.connections = [None] * len(newblk.docks)
- if newblk.name in DEFAULTS:
- for i, argvalue in enumerate(DEFAULTS[newblk.name]):
+ if newblk.name in default_values:
+ if defaults == None:
+ defaults = default_values[newblk.name]
+ for i, argvalue in enumerate(defaults):
# skip the first dock position since it is always a connector
dock = newblk.docks[i + 1]
argname = dock[0]
@@ -1186,7 +1229,7 @@ class TurtleArtWindow():
argname = argvalue
(sx, sy) = newspr.get_xy()
if argname is not None:
- if argname in CONTENT_BLOCKS:
+ if argname in content_blocks:
argblk = Block(self.block_list, self.sprite_list,
argname, 0, 0, 'block', [argvalue],
self.block_scale)
@@ -1218,8 +1261,7 @@ class TurtleArtWindow():
def process_data(self, block_data, offset=0):
""" Process block_data (from a macro, a file, or the clipboard). """
- if offset != 0:
- _logger.debug("offset is %d" % (offset))
+
# Create the blocks (or turtle).
blocks = []
for blk in block_data:
@@ -1238,7 +1280,8 @@ class TurtleArtWindow():
else:
cons.append(blocks[c])
else:
- _logger.debug("connection error %s" % (str(block_data[i])))
+ debug_output("connection error %s" % (str(block_data[i])),
+ self.running_sugar)
cons.append(None)
elif blocks[i].connections == 'check':
# Convert old-style boolean and arithmetic blocks
@@ -1249,7 +1292,7 @@ class TurtleArtWindow():
else:
cons.append(blocks[c])
# If the boolean op was connected, readjust the plumbing.
- if blocks[i].name in BOOLEAN_STYLE:
+ if blocks[i].name in block_styles['boolean-style']:
if block_data[i][4][0] is not None:
c = block_data[i][4][0]
cons[0] = blocks[block_data[c][4][0]]
@@ -1262,7 +1305,8 @@ class TurtleArtWindow():
blocks[c].connections[3] = None
else:
# Connection was to a block we haven't seen yet.
- _logger.debug("Warning: dock to the future")
+ debug_output("Warning: dock to the future",
+ self.running_sugar)
else:
if block_data[i][4][0] is not None:
c = block_data[i][4][0]
@@ -1276,10 +1320,12 @@ class TurtleArtWindow():
blocks[c].connections[1] = None
else:
# Connection was to a block we haven't seen yet.
- _logger.debug("Warning: dock to the future")
+ debug_output("Warning: dock to the future",
+ self.running_sugar)
else:
- _logger.debug("Warning: unknown connection state %s" % \
- (str(blocks[i].connections)))
+ debug_output("Warning: unknown connection state %s" % \
+ (str(blocks[i].connections)),
+ self.running_sugar)
blocks[i].connections = cons[:]
# Block sizes and shapes may have changed.
@@ -1310,7 +1356,7 @@ class TurtleArtWindow():
return
(sx, sy) = blk.spr.get_xy()
for i, c in enumerate(blk.connections):
- if i > 0 and c is not None:
+ if i > 0 and c is not None and i < len(blk.docks):
bdock = blk.docks[i]
for j in range(len(c.docks)):
if j < len(c.connections) and c.connections[j] == blk:
@@ -1322,8 +1368,8 @@ class TurtleArtWindow():
def _turtle_pressed(self, x, y):
(tx, ty) = self.selected_turtle.get_xy()
- w = self.active_turtle.spr.rect.width / 2
- h = self.active_turtle.spr.rect.height / 2
+ 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
@@ -1349,17 +1395,29 @@ class TurtleArtWindow():
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())
if dtype == 'move':
- dx = x - dragx - sx
- dy = y - dragy - sy
+ dx = x - dragx - sx + self.selected_turtle.spr.rect.width / 2
+ dy = y - dragy - sy + self.selected_turtle.spr.rect.width / 2
self.selected_turtle.spr.set_layer(TOP_LAYER)
- self.selected_turtle.move((sx + dx, sy + dy))
+ 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)
+ self.canvas.setpen(True)
+ else:
+ self.canvas.setxy(tx, ty)
else:
- dx = x - sx - self.active_turtle.spr.rect.width / 2
- dy = y - sy - self.active_turtle.spr.rect.height / 2
+ 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)
self.lc.update_label_value('heading', self.canvas.heading)
+ if self.sharing(): # share turtle rotation
+ self.send_event("r|%s" % (
+ data_to_string([self.selected_turtle.get_name(),
+ round_int(self.canvas.heading)])))
# If we are hoving, show popup help.
elif self.drag_group is None:
@@ -1468,27 +1526,27 @@ class TurtleArtWindow():
def _do_show_popup(self, block_name):
""" Fetch the help text and display it. """
- if block_name in SPECIAL_NAMES:
- block_name_s = SPECIAL_NAMES[block_name]
- elif block_name in BLOCK_NAMES:
- block_name_s = BLOCK_NAMES[block_name][0]
+ if block_name in special_names:
+ special_block_name = special_names[block_name]
+ elif block_name in block_names:
+ special_block_name = block_names[block_name][0]
elif block_name in TOOLBAR_SHAPES:
- block_name_s = ''
+ special_block_name = ''
else:
- block_name_s = _(block_name)
- if block_name in HELP_STRINGS:
- if block_name_s == '':
- label = HELP_STRINGS[block_name]
+ special_block_name = _(block_name)
+ if block_name in help_strings:
+ if special_block_name == '':
+ label = help_strings[block_name]
else:
- label = block_name_s + ": " + HELP_STRINGS[block_name]
+ label = special_block_name + ": " + help_strings[block_name]
else:
- label = block_name_s
+ label = special_block_name
if self.running_sugar:
self.activity.hover_help_label.set_text(label)
self.activity.hover_help_label.show()
else:
if self.interactive_mode:
- self.win.set_title(_("Turtle Art") + " — " + label)
+ self.parent.set_title(_("Turtle Art") + " — " + label)
return 0
def _buttonrelease_cb(self, win, event):
@@ -1514,14 +1572,15 @@ class TurtleArtWindow():
else:
self.selected_turtle.hide()
self.turtles.remove_from_dict(k)
+ self.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.selected_turtle = None
- self.active_turtle = self.turtles.get_turtle(
- self.default_turtle_name)
+ if self.active_turtle is None:
+ self.canvas.set_turtle(self.default_turtle_name)
return
# If we don't have a group of blocks, then there is nothing to do.
@@ -1557,6 +1616,30 @@ class TurtleArtWindow():
if self.block_operation == 'click':
self._click_block(x, y)
+ def remote_turtle(self, name):
+ ''' Is this a remote turtle? '''
+ if name == self.nick:
+ return False
+ if hasattr(self, 'remote_turtle_dictionary') and \
+ name in self.remote_turtle_dictionary:
+ return True
+ return False
+
+ def label_remote_turtle(self, name, colors=['#A0A0A0', '#C0C0C0']):
+ ''' Add a label to remote turtles '''
+ turtle = self.turtles.get_turtle(name)
+ if turtle is not None:
+ turtle.label_block = Block(self.block_list,
+ self.sprite_list, 'turtle-label', 0, 0,
+ 'label', [], 1.0 / self.scale,
+ colors)
+ turtle.label_block.spr.set_label_attributes(6.0 / self.scale)
+ if len(name) > 6:
+ turtle.label_block.spr.set_label(name[0:4] + '…')
+ else:
+ turtle.label_block.spr.set_label(name)
+ turtle.show()
+
def _move_turtle(self, x, y):
""" Move the selected turtle to (x, y). """
(cx, cy) = self.canvas.canvas.get_xy()
@@ -1570,8 +1653,6 @@ class TurtleArtWindow():
self.canvas.xcor / self.coord_scale)
self.lc.update_label_value('ycor',
self.canvas.ycor / self.coord_scale)
- if len(self.lc.value_blocks['see']) > 0:
- self.lc.see()
def _click_block(self, x, y):
""" Click block: lots of special cases to handle... """
@@ -1584,7 +1665,9 @@ class TurtleArtWindow():
self.saved_string = blk.spr.labels[0]
blk.spr.labels[0] += CURSOR
- elif blk.name in BOX_STYLE_MEDIA and blk.name != 'camera':
+ elif blk.name in block_styles['box-style-media'] and \
+ blk.name != 'camera':
+ # TODO: isolate reference to camera
self._import_from_journal(self.selected_blk)
if blk.name == 'journal' and self.running_sugar:
self._load_description_block(blk)
@@ -1597,7 +1680,8 @@ class TurtleArtWindow():
dx = 20
blk.expand_in_x(dx)
else:
- dx = 0
+ self._run_stack(blk)
+ return
for gblk in group:
if gblk != blk:
gblk.spr.move_relative((dx * blk.scale, 0))
@@ -1610,13 +1694,14 @@ class TurtleArtWindow():
dy = 20
blk.expand_in_y(dy)
else:
- dy = 0
+ self._run_stack(blk)
+ return
for gblk in group:
if gblk != blk:
gblk.spr.move_relative((0, dy * blk.scale))
grow_stack_arm(find_sandwich_top(blk))
- elif blk.name in EXPANDABLE_BLOCKS:
+ elif blk.name in expandable_blocks:
# Connection may be lost during expansion, so store it...
blk0 = blk.connections[0]
if blk0 is not None:
@@ -1628,11 +1713,10 @@ class TurtleArtWindow():
dy = 20
blk.expand_in_y(dy)
else:
- self._start_audiograb()
self._run_stack(blk)
return
- if blk.name in BOOLEAN_STYLE:
+ if blk.name in block_styles['boolean-style']:
self._expand_boolean(blk, blk.connections[1], dy)
else:
self._expand_expandable(blk, blk.connections[1], dy)
@@ -1664,17 +1748,20 @@ class TurtleArtWindow():
dy = blk.add_arg()
blk.primitive = 'userdefined2'
blk.name = 'userdefined2args'
+ self._resize_skin(blk)
elif blk.name == 'userdefined2args':
dy = blk.add_arg(False)
blk.primitive = 'userdefined3'
blk.name = 'userdefined3args'
+ self._resize_skin(blk)
else:
dy = blk.add_arg()
for gblk in group:
gblk.spr.move_relative((0, dy))
blk.connections.append(blk.connections[n - 1])
argname = blk.docks[n - 1][0]
- argvalue = DEFAULTS[blk.name][len(DEFAULTS[blk.name]) - 1]
+ argvalue = default_values[blk.name][len(
+ default_values[blk.name]) - 1]
argblk = Block(self.block_list, self.sprite_list, argname,
0, 0, 'block', [argvalue], self.block_scale)
argdock = argblk.docks[0]
@@ -1685,28 +1772,26 @@ class TurtleArtWindow():
argblk.spr.set_layer(TOP_LAYER)
argblk.connections = [blk, None]
blk.connections[n - 1] = argblk
- if blk.name in NUMBER_STYLE_VAR_ARG:
+ if blk.name in block_styles['number-style-var-arg']:
self._cascade_expandable(blk)
grow_stack_arm(find_sandwich_top(blk))
elif blk.name in PYTHON_SKIN:
self._import_py()
else:
- self._start_audiograb()
self._run_stack(blk)
- elif blk.name in ['sandwichtop_no_arm_no_label',
+ elif blk.name in ['sandwichtop_no_arm_no_label',
'sandwichtop_no_arm']:
restore_stack(blk)
elif blk.name in COLLAPSIBLE:
top = find_sandwich_top(blk)
if collapsed(blk):
- restore_stack(top) # depreciated (bottom block is invisible)
+ restore_stack(top) # deprecated (bottom block is invisible)
elif top is not None:
collapse_stack(top)
else:
- self._start_audiograb()
self._run_stack(blk)
def _expand_boolean(self, blk, blk2, dy):
@@ -1726,19 +1811,27 @@ class TurtleArtWindow():
for gblk in find_group(blk):
if gblk not in group:
gblk.spr.move_relative((0, dy * blk.scale))
- if blk.name in COMPARE_STYLE:
+ if blk.name in block_styles['compare-style']:
for gblk in find_group(blk):
gblk.spr.move_relative((0, -dy * blk.scale))
+ def _number_style(self, name):
+ if name in block_styles['number-style']:
+ return True
+ if name in block_styles['number-style-porch']:
+ return True
+ if name in block_styles['number-style-block']:
+ return True
+ if name in block_styles['number-style-var-arg']:
+ return True
+ return False
+
def _cascade_expandable(self, blk):
""" If expanding/shrinking a block, cascade. """
- while blk.name in NUMBER_STYLE or \
- blk.name in NUMBER_STYLE_PORCH or \
- blk.name in NUMBER_STYLE_BLOCK or \
- blk.name in NUMBER_STYLE_VAR_ARG:
+ while self._number_style(blk.name):
if blk.connections[0] is None:
break
- if blk.connections[0].name in EXPANDABLE_BLOCKS:
+ if blk.connections[0].name in expandable_blocks:
if blk.connections[0].connections.index(blk) != 1:
break
blk = blk.connections[0]
@@ -1755,7 +1848,7 @@ class TurtleArtWindow():
for gblk in find_group(blk):
if gblk not in group:
gblk.spr.move_relative((0, dy * blk.scale))
- if blk.name in COMPARE_STYLE:
+ if blk.name in block_styles['compare-style']:
for gblk in find_group(blk):
gblk.spr.move_relative((0, -dy * blk.scale))
else:
@@ -1790,7 +1883,8 @@ class TurtleArtWindow():
""" Run a stack of blocks. """
if blk is None:
return
- self.lc.ag = None
+ self.lc.find_value_blocks() # Are there blocks to update?
+ self._start_plugins() # Let the plugins know we are running.
top = find_top_block(blk)
self.lc.run_blocks(top, self.just_blocks(), True)
if self.interactive_mode:
@@ -1848,17 +1942,18 @@ class TurtleArtWindow():
selected_block.connections[best_selected_block_dockn] = \
best_destination
- if best_destination.name in BOOLEAN_STYLE:
+ if best_destination.name in block_styles['boolean-style']:
if best_destination_dockn == 2 and \
- selected_block.name in COMPARE_STYLE:
+ selected_block.name in block_styles['compare-style']:
dy = selected_block.ey - best_destination.ey
best_destination.expand_in_y(dy)
self._expand_boolean(best_destination, selected_block, dy)
- elif best_destination.name in EXPANDABLE_BLOCKS and \
+ elif best_destination.name in expandable_blocks and \
best_destination_dockn == 1:
dy = 0
- if (selected_block.name in EXPANDABLE_BLOCKS or
- selected_block.name in NUMBER_STYLE_VAR_ARG):
+ if (selected_block.name in expandable_blocks or
+ selected_block.name in block_styles[
+ 'number-style-var-arg']):
if selected_block.name == 'myfunc2arg':
dy = 40 + selected_block.ey - best_destination.ey
elif selected_block.name == 'myfunc3arg':
@@ -1877,6 +1972,8 @@ class TurtleArtWindow():
def _disconnect(self, blk):
""" Disconnect block from stack above it. """
+ if blk is None:
+ return
if blk.connections[0] is None:
return
if collapsed(blk):
@@ -1886,12 +1983,12 @@ class TurtleArtWindow():
c = blk2.connections.index(blk)
blk2.connections[c] = None
- if blk2.name in BOOLEAN_STYLE:
+ if blk2.name in block_styles['boolean-style']:
if c == 2 and blk2.ey > 0:
dy = -blk2.ey
blk2.expand_in_y(dy)
self._expand_boolean(blk2, blk, dy)
- elif blk2.name in EXPANDABLE_BLOCKS and c == 1:
+ elif blk2.name in expandable_blocks and c == 1:
if blk2.ey > 0:
dy = blk2.reset_y()
if dy != 0:
@@ -1976,7 +2073,6 @@ class TurtleArtWindow():
""" Keyboard """
keyname = gtk.gdk.keyval_name(event.keyval)
keyunicode = gtk.gdk.keyval_to_unicode(event.keyval)
-
if event.get_state() & gtk.gdk.MOD1_MASK:
alt_mask = True
alt_flag = 'T'
@@ -1996,9 +2092,9 @@ class TurtleArtWindow():
if keyname == "p":
self.hideshow_button()
elif keyname == 'q':
- if self.audio_started:
- self.audiograb.stop_grabbing()
- stop_media(self.lc)
+ self._plugins_quit()
+ if self.gst_available:
+ stop_media(self.lc)
exit()
elif keyname == 'g':
self._align_to_grid()
@@ -2077,7 +2173,8 @@ class TurtleArtWindow():
oldleft, oldright = \
self.selected_blk.spr.labels[0].split(CURSOR)
except ValueError:
- _logger.debug("[%s]" % self.selected_blk.spr.labels[0])
+ debug_output("[%s]" % self.selected_blk.spr.labels[0],
+ self.running_sugar)
oldleft = self.selected_blk.spr.labels[0]
oldright = ''
else:
@@ -2286,7 +2383,8 @@ class TurtleArtWindow():
f.close()
id = fname
except IOError:
- _logger.error("Unable to read Python code from %s" % (fname))
+ error_output("Unable to read Python code from %s" % (fname),
+ self.running_sugar)
return id
# if we are running Sugar, copy the file into the Journal
@@ -2302,7 +2400,8 @@ class TurtleArtWindow():
datastore.write(dsobject)
id = dsobject.object_id
except IOError:
- _logger.error("Error copying %s to the datastore" % (fname))
+ error_output("Error copying %s to the datastore" % (fname),
+ self.running_sugar)
id = None
dsobject.destroy()
@@ -2327,12 +2426,14 @@ class TurtleArtWindow():
""" Read the Python code from the Journal object """
self.python_code = None
try:
- _logger.debug("opening %s " % dsobject.file_path)
+ debug_output("opening %s " % dsobject.file_path,
+ self.running_sugar)
file_handle = open(dsobject.file_path, "r")
self.python_code = file_handle.read()
file_handle.close()
except IOError:
- _logger.debug("couldn't open %s" % dsobject.file_path)
+ debug_output("couldn't open %s" % dsobject.file_path,
+ self.running_sugar)
if blk is None:
blk = self.selected_blk
if blk is not None:
@@ -2356,7 +2457,7 @@ class TurtleArtWindow():
def new_project(self):
""" Start a new project """
- stop_logo(self)
+ self.lc.stop_logo()
self._loaded_project = ""
# Put current project in the trash.
while len(self.just_blocks()) > 0:
@@ -2377,8 +2478,9 @@ class TurtleArtWindow():
saved_project_data = f.read()
f.close()
except:
- _logger.debug("problem loading saved project data from %s" % \
- (self._loaded_project))
+ debug_output("problem loading saved project data from %s" % \
+ (self._loaded_project),
+ self.running_sugar)
saved_project_data = ""
current_project_data = data_to_string(self.assemble_data_to_save())
@@ -2409,14 +2511,13 @@ class TurtleArtWindow():
if blk[1] == 'turtle':
self.load_turtle(blk)
return True
- elif type(blk[1]) == list and blk[1][0] == 'turtle':
- self.load_turtle(blk, blk[1][1])
+ elif type(blk[1]) in [list, tuple] and blk[1][0] == 'turtle':
+ if blk[1][1] == DEFAULT_TURTLE:
+ if self.nick is not None and self.nick is not '':
+ self.load_turtle(blk, self.nick)
+ else:
+ self.load_turtle(blk, blk[1][1])
return True
- elif type(blk[1]) == tuple:
- _btype, _key = blk[1]
- if _btype == 'turtle':
- self.load_turtle(blk, _key)
- return True
return False
def load_turtle(self, blk, key=1):
@@ -2438,7 +2539,7 @@ class TurtleArtWindow():
btype, value = btype
elif type(btype) == list:
btype, value = btype[0], btype[1]
- if btype in CONTENT_BLOCKS or btype in COLLAPSIBLE:
+ if btype in content_blocks or btype in COLLAPSIBLE:
if btype == 'number':
try:
values = [round_int(value)]
@@ -2467,16 +2568,17 @@ class TurtleArtWindow():
'block', values, self.block_scale)
# Some blocks get transformed.
- if btype in BASIC_STYLE_VAR_ARG and value is not None:
+ if btype in block_styles['basic-style-var-arg'] and value is not None:
# Is there code stored in this userdefined block?
- if value > 0: # catch depreciated format (#2501)
+ if value > 0: # catch deprecated format (#2501)
self.python_code = None
if self.running_sugar:
try:
dsobject = datastore.get(value)
- except: # Should be IOError, but dbus error is raised
+ except: # Should be IOError, but dbus error is raised
dsobject = None
- _logger.debug("couldn't get dsobject %s" % value)
+ debug_output("couldn't get dsobject %s" % value,
+ self.running_sugar)
if dsobject is not None:
self.load_python_code_from_journal(dsobject, blk)
else:
@@ -2493,9 +2595,9 @@ class TurtleArtWindow():
elif btype == 'start': # block size is saved in start block
if value is not None:
self.block_scale = value
- elif btype in EXPANDABLE or btype in EXPANDABLE_BLOCKS or \
+ elif btype in EXPANDABLE or btype in expandable_blocks or \
btype in EXPANDABLE_ARGS or btype == 'nop':
- if btype == 'vspace' or btype in EXPANDABLE_BLOCKS:
+ if btype == 'vspace' or btype in expandable_blocks:
if value is not None:
blk.expand_in_y(value)
elif btype == 'hspace' or btype == 'identity2':
@@ -2514,7 +2616,8 @@ class TurtleArtWindow():
self._block_skin('pythonon', blk)
else:
self._block_skin('pythonoff', blk)
- elif btype in BOX_STYLE_MEDIA and blk.spr is not None:
+ elif btype in block_styles['box-style-media'] and blk.spr is not None:
+ # TODO: isolate reference to camera
if len(blk.values) == 0 or blk.values[0] == 'None' or \
blk.values[0] is None or btype == 'camera':
self._block_skin(btype + 'off', blk)
@@ -2541,8 +2644,8 @@ class TurtleArtWindow():
x, y = self._calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
except:
- _logger.debug("Couldn't open dsobject (%s)" % \
- (blk.values[0]))
+ debug_output("Couldn't open dsobject (%s)" % \
+ (blk.values[0]), self.running_sugar)
self._block_skin('journaloff', blk)
else:
if not movie_media_type(blk.values[0][-4:]):
@@ -2605,14 +2708,15 @@ class TurtleArtWindow():
for _i, _blk in enumerate(_blks):
_blk.id = _i
for _blk in _blks:
- if _blk.name in CONTENT_BLOCKS or _blk.name in COLLAPSIBLE:
+ if _blk.name in content_blocks or _blk.name in COLLAPSIBLE:
if len(_blk.values) > 0:
_name = (_blk.name, _blk.values[0])
else:
_name = (_blk.name)
- elif _blk.name in BASIC_STYLE_VAR_ARG and len(_blk.values) > 0:
+ elif _blk.name in block_styles['basic-style-var-arg'] and \
+ len(_blk.values) > 0:
_name = (_blk.name, _blk.values[0])
- elif _blk.name in EXPANDABLE or _blk.name in EXPANDABLE_BLOCKS or\
+ elif _blk.name in EXPANDABLE or _blk.name in expandable_blocks or\
_blk.name in EXPANDABLE_ARGS:
_ex, _ey = _blk.get_expand_x_y()
if _ex > 0:
@@ -2637,12 +2741,16 @@ class TurtleArtWindow():
_data.append((_blk.id, _name, _sx - self.canvas.cx,
_sy - self.canvas.cy, connections))
if save_turtle:
- for _turtle in iter(self.turtles.dict):
- self.canvas.set_turtle(_turtle)
- _data.append((-1, ['turtle', _turtle],
- self.canvas.xcor, self.canvas.ycor,
- self.canvas.heading, self.canvas.color,
- self.canvas.shade, self.canvas.pensize))
+ for turtle in iter(self.turtles.dict):
+ # Don't save remote turtles
+ if not self.remote_turtle(turtle):
+ # Save default turtle as 'Yertle'
+ if turtle == self.nick:
+ turtle = DEFAULT_TURTLE
+ _data.append((-1, ['turtle', turtle],
+ self.canvas.xcor, self.canvas.ycor,
+ self.canvas.heading, self.canvas.color,
+ self.canvas.shade, self.canvas.pensize))
return _data
def display_coordinates(self):
@@ -2655,13 +2763,13 @@ class TurtleArtWindow():
(_("xcor"), x, _("ycor"), y, _("heading"), h))
self.activity.coordinates_label.show()
elif self.interactive_mode:
- self.win.set_title("%s — %s: %d %s: %d %s: %d" % \
+ self.parent.set_title("%s — %s: %d %s: %d %s: %d" % \
(_("Turtle Art"), _("xcor"), x, _("ycor"), y, _("heading"), h))
def showlabel(self, shp, label=''):
""" Display a message on a status block """
if not self.interactive_mode:
- _logger.debug(label)
+ debug_output(label, self.running_sugar)
return
if shp == 'syntaxerror' and str(label) != '':
if str(label)[1:] in self.status_shapes:
@@ -2683,7 +2791,7 @@ class TurtleArtWindow():
self.status_spr.move((PALETTE_WIDTH, self.height - 200))
def calc_position(self, template):
- """ Relative placement of portfolio objects (depreciated) """
+ """ Relative placement of portfolio objects (deprecated) """
w, h, x, y, dx, dy = TEMPLATES[template]
x *= self.canvas.width
y *= self.canvas.height
@@ -2705,49 +2813,30 @@ class TurtleArtWindow():
def save_as_image(self, name="", svg=False, pixbuf=None):
""" Grab the current canvas and save it. """
+ if svg:
+ suffix = '.svg'
+ else:
+ suffix = '.png'
if not self.interactive_mode:
- save_picture(self.canvas, name[:-3] + ".png")
+ save_picture(self.canvas, name[:-3] + suffix)
return
- """
- self.color_map = self.window.get_colormap()
- new_pix = pixbuf.get_from_drawable(self.window, self.color_map,
- 0, 0, 0, 0,
- self.width, self.height)
- new_pix.save(name[:-3] + ".png", "png")
- """
-
if self.running_sugar:
- if svg:
- if len(name) == 0:
- filename = "ta.svg"
- else:
- filename = name + ".svg"
+ if len(name) == 0:
+ filename = 'ta' + suffix
else:
- if len(name) == 0:
- filename = "ta.png"
- else:
- filename = name + ".png"
+ filename = name + suffix
datapath = get_path(self.activity, 'instance')
elif len(name) == 0:
- name = "ta"
+ name = 'ta'
if self.save_folder is not None:
self.load_save_folder = self.save_folder
- if svg:
- filename, self.load_save_folder = get_save_name('.svg',
- self.load_save_folder,
- name)
- else:
- filename, self.load_save_folder = get_save_name('.png',
- self.load_save_folder,
- name)
+ filename, self.load_save_folder = get_save_name(
+ suffix, self.load_save_folder, name)
datapath = self.load_save_folder
else:
datapath = os.getcwd()
- if svg:
- filename = name + ".svg"
- else:
- filename = name + ".png"
+ filename = name + suffix
if filename is None:
return
@@ -2864,3 +2953,36 @@ class TurtleArtWindow():
w, h = self._calc_w_h('descriptionoff', blk.spr)
x, y = self._calc_image_offset('descriptionoff', blk.spr, w, h)
blk.scale_image(x, y, w, h)
+
+
+def dock_dx_dy(block1, dock1n, block2, dock2n):
+ """ Find the distance between the dock points of two blocks. """
+ _dock1 = block1.docks[dock1n]
+ _dock2 = block2.docks[dock2n]
+ _d1type, _d1dir, _d1x, _d1y = _dock1[0:4]
+ _d2type, _d2dir, _d2x, _d2y = _dock2[0:4]
+ if block1 == block2:
+ return (100, 100)
+ if _d1dir == _d2dir:
+ return (100, 100)
+ if (_d2type is not 'number') or (dock2n is not 0):
+ if block1.connections is not None and \
+ dock1n < len(block1.connections) and \
+ block1.connections[dock1n] is not None:
+ return (100, 100)
+ if block2.connections is not None and \
+ dock2n < len(block2.connections) and \
+ block2.connections[dock2n] is not None:
+ return (100, 100)
+ if _d1type != _d2type:
+ if block1.name in STRING_OR_NUMBER_ARGS:
+ if _d2type == 'number' or _d2type == 'string':
+ pass
+ elif block1.name in CONTENT_ARGS:
+ if _d2type in content_blocks:
+ pass
+ else:
+ return (100, 100)
+ (_b1x, _b1y) = block1.spr.get_xy()
+ (_b2x, _b2y) = block2.spr.get_xy()
+ return ((_b1x + _d1x) - (_b2x + _d2x), (_b1y + _d1y) - (_b2y + _d2y))