Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter Bender <walter@sugarlabs.org>2014-02-10 23:09:38 (GMT)
committer Walter Bender <walter@sugarlabs.org>2014-02-10 23:09:38 (GMT)
commit1bf93b67e874cb5b89b53f577ab476377390485b (patch)
tree903ea636a0da87cbd7128980ab8e4f26a73fa0c1
parent6592663e2e956c5d6557d3eb006b119b5d59ebfe (diff)
v199
-rw-r--r--TurtleArt/sprites.py18
-rw-r--r--TurtleArt/tablock.py10
-rw-r--r--TurtleArt/taconstants.py23
-rw-r--r--TurtleArt/tagplay.py46
-rw-r--r--TurtleArt/talogo.py63
-rw-r--r--TurtleArt/tapaletteview.py409
-rw-r--r--TurtleArt/taselector.py108
-rwxr-xr-xTurtleArt/tasprite_factory.py13
-rw-r--r--TurtleArt/taturtle.py7
-rw-r--r--TurtleArt/tatype.py3
-rw-r--r--TurtleArt/tautils.py43
-rw-r--r--TurtleArt/tawindow.py540
-rwxr-xr-xturtleblocks.py15
13 files changed, 778 insertions, 520 deletions
diff --git a/TurtleArt/sprites.py b/TurtleArt/sprites.py
index 3f5d7df..c8a0f6c 100644
--- a/TurtleArt/sprites.py
+++ b/TurtleArt/sprites.py
@@ -167,8 +167,8 @@ class Sprite:
self.rect = gtk.gdk.Rectangle(int(x), int(y), 0, 0)
self._scale = [12]
self._rescale = [True]
- self._horiz_align = ["center"]
- self._vert_align = ["middle"]
+ self._horiz_align = ['center']
+ self._vert_align = ['middle']
self._x_pos = [None]
self._y_pos = [None]
self._fd = None
@@ -269,7 +269,7 @@ class Sprite:
self._extend_labels_array(i)
if isinstance(new_label, (str, unicode)):
# pango doesn't like nulls
- self.labels[i] = new_label.replace("\0", " ")
+ self.labels[i] = new_label.replace('\0', ' ')
else:
self.labels[i] = str(new_label)
self.inval()
@@ -285,7 +285,7 @@ class Sprite:
if self._color is None:
self._color = (0., 0., 0.)
while len(self.labels) < i + 1:
- self.labels.append(" ")
+ self.labels.append(' ')
self._scale.append(self._scale[0])
self._rescale.append(self._rescale[0])
self._horiz_align.append(self._horiz_align[0])
@@ -312,8 +312,8 @@ class Sprite:
int('0x' + rgb[5:7], 16) / 256.)
return
- def set_label_attributes(self, scale, rescale=True, horiz_align="center",
- vert_align="middle", x_pos=None, y_pos=None, i=0):
+ def set_label_attributes(self, scale, rescale=True, horiz_align='center',
+ vert_align='middle', x_pos=None, y_pos=None, i=0):
''' Set the various label attributes '''
self._extend_labels_array(i)
self._scale[i] = scale
@@ -407,7 +407,7 @@ class Sprite:
w = pl.get_size()[0] / pango.SCALE
if self._x_pos[i] is not None:
x = int(self.rect.x + self._x_pos[i])
- elif self._horiz_align[i] == "center":
+ elif self._horiz_align[i] == 'center':
x = int(self.rect.x + self._margins[0] + (my_width - w) / 2)
elif self._horiz_align[i] == 'left':
x = int(self.rect.x + self._margins[0])
@@ -416,9 +416,9 @@ class Sprite:
h = pl.get_size()[1] / pango.SCALE
if self._y_pos[i] is not None:
y = int(self.rect.y + self._y_pos[i])
- elif self._vert_align[i] == "middle":
+ elif self._vert_align[i] == 'middle':
y = int(self.rect.y + self._margins[1] + (my_height - h) / 2)
- elif self._vert_align[i] == "top":
+ elif self._vert_align[i] == 'top':
y = int(self.rect.y + self._margins[1])
else: # bottom
y = int(self.rect.y + self.rect.height - h - self._margins[3])
diff --git a/TurtleArt/tablock.py b/TurtleArt/tablock.py
index 5f3315a..c257a14 100644
--- a/TurtleArt/tablock.py
+++ b/TurtleArt/tablock.py
@@ -43,19 +43,21 @@ class Media(object):
ALL_TYPES = ('media', 'audio', 'video', 'descr', 'camera', 'camera1')
- def __init__(self, type_, value=None):
+ def __init__(self, media_type, value=None):
"""
- type_ --- a string that indicates the kind of media:
+ media_type --- a string that indicates the kind of media:
media --- image
audio --- audio file
video --- video
descr --- Journal description
camera, camera1 --- camera snapshot
value --- a file path or a reference to a Sugar datastore object """
- if type_ not in Media.ALL_TYPES:
+ if media_type == 'image':
+ media_type = 'media'
+ if media_type not in Media.ALL_TYPES:
raise ValueError("Media.type must be one of " +
repr(Media.ALL_TYPES))
- self.type = type_
+ self.type = media_type
self.value = value
def __str__(self):
diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py
index a8fc046..0a3cc23 100644
--- a/TurtleArt/taconstants.py
+++ b/TurtleArt/taconstants.py
@@ -151,6 +151,26 @@ REVERSE_KEY_DICT = {
}
+class ColorObj(object):
+ def __init__(self, color):
+ self.color = color
+
+ def __int__(self):
+ if self.color.color is None:
+ return int(self.color.shade)
+ else:
+ return int(self.color.color)
+
+ def __float__(self):
+ return float(int(self))
+
+ def __str__(self):
+ return str(self.color.name)
+
+ def __repr__(self):
+ return str(self.color.name)
+
+
class Color(object):
""" A color used in block programs (e.g., as pen color). """
@@ -176,6 +196,9 @@ class Color(object):
def get_number_string(self):
return str(int(self))
+ def get_number_name(self):
+ return str(self.name)
+
def __str__(self):
return str(self.name)
diff --git a/TurtleArt/tagplay.py b/TurtleArt/tagplay.py
index 9e9f821..fc3ee9e 100644
--- a/TurtleArt/tagplay.py
+++ b/TurtleArt/tagplay.py
@@ -22,8 +22,6 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
-
-import logging
import os
import pygtk
@@ -36,6 +34,8 @@ import gst
import gst.interfaces
import gtk
+from tautils import error_output, debug_output
+
def play_audio_from_file(lc, file_path):
""" Called from Show block of audio media """
@@ -102,7 +102,7 @@ class Gplay():
UPDATE_INTERVAL = 500
def __init__(self, lc, x, y, w, h):
-
+ self.running_sugar = lc.tw.running_sugar
self.player = None
self.uri = None
self.playlist = []
@@ -118,7 +118,7 @@ class Gplay():
self.bin.add(self.videowidget)
self.bin.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
self.bin.set_decorated(False)
- if lc.tw.running_sugar:
+ if self.running_sugar:
self.bin.set_transient_for(lc.tw.activity)
self.bin.move(x, y)
@@ -128,14 +128,15 @@ class Gplay():
self._want_document = True
def _player_eos_cb(self, widget):
- logging.debug('end of stream')
+ debug_output('end of stream', self.running_sugar)
# Make sure player is stopped after EOS
self.player.stop()
def _player_error_cb(self, widget, message, detail):
self.player.stop()
self.player.set_uri(None)
- logging.debug('Error: %s - %s' % (message, detail))
+ error_output('Error: %s - %s' % (message, detail),
+ self.running_sugar)
def _player_stream_info_cb(self, widget, stream_info):
if not len(stream_info) or self.got_stream_info:
@@ -157,22 +158,23 @@ class Gplay():
return False
self.playlist.append('file://' + os.path.abspath(file_path))
if not self.player:
- # lazy init the player so that videowidget is realized
- # and has a valid widget allocation
- self.player = GstPlayer(self.videowidget)
+ # Lazy init the player so that videowidget is realized
+ # and has a valid widget allocation.
+ self.player = GstPlayer(self.videowidget, self.running_sugar)
self.player.connect('eos', self._player_eos_cb)
self.player.connect('error', self._player_error_cb)
self.player.connect('stream-info', self._player_stream_info_cb)
try:
if not self.currentplaying:
- logging.info('Playing: %s' % (self.playlist[0]))
+ debug_output('Playing: %s' % (self.playlist[0]),
+ self.running_sugar)
self.player.set_uri(self.playlist[0])
self.currentplaying = 0
self.play_toggled()
- self.show_all()
- except:
- logging.error('Error playing %s' % (self.playlist[0]))
+ except Exception, e:
+ error_output('Error playing %s: %s' % (self.playlist[0], e),
+ self.running_sugar)
return False
def play_toggled(self):
@@ -191,9 +193,10 @@ class GstPlayer(gobject.GObject):
'eos': (gobject.SIGNAL_RUN_FIRST, None, []),
'stream-info': (gobject.SIGNAL_RUN_FIRST, None, [object])}
- def __init__(self, videowidget):
+ def __init__(self, videowidget, running_sugar):
gobject.GObject.__init__(self)
+ self.running_sugar = running_sugar
self.playing = False
self.error = False
@@ -224,7 +227,8 @@ class GstPlayer(gobject.GObject):
t = message.type
if t == gst.MESSAGE_ERROR:
err, debug = message.parse_error()
- logging.debug('Error: %s - %s' % (err, debug))
+ error_output('Error: %s - %s' % (err, debug),
+ self.running_sugar)
self.error = True
self.emit('eos')
self.playing = False
@@ -234,11 +238,10 @@ class GstPlayer(gobject.GObject):
self.playing = False
elif t == gst.MESSAGE_STATE_CHANGED:
old, new, pen = message.parse_state_changed()
- if old == gst.STATE_READY and new == gst.STATE_PAUSED:
+ if old == gst.STATE_READY and new == gst.STATE_PAUSED and \
+ hasattr(self.player.props, 'stream_info_value_array'):
self.emit('stream-info',
self.player.props.stream_info_value_array)
- # else:
- # logging.debug(message.type)
def _init_video_sink(self):
self.bin = gst.Bin()
@@ -275,19 +278,18 @@ class GstPlayer(gobject.GObject):
def pause(self):
self.player.set_state(gst.STATE_PAUSED)
self.playing = False
- logging.debug('pausing player')
+ # debug_output('pausing player', self.running_sugar)
def play(self):
self.player.set_state(gst.STATE_PLAYING)
self.playing = True
self.error = False
- logging.debug('playing player')
+ # debug_output('playing player', self.running_sugar)
def stop(self):
self.player.set_state(gst.STATE_NULL)
self.playing = False
- logging.debug('stopped player')
- # return False
+ # debug_output('stopped player', self.running_sugar)
def get_state(self, timeout=1):
return self.player.get_state(timeout=timeout)
diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py
index 7307b99..b3435e3 100644
--- a/TurtleArt/talogo.py
+++ b/TurtleArt/talogo.py
@@ -41,11 +41,12 @@ except ImportError:
import traceback
from tablock import (Block, Media, media_blocks_dictionary)
-from taconstants import (TAB_LAYER, DEFAULT_SCALE, ICON_SIZE)
+from taconstants import (TAB_LAYER, DEFAULT_SCALE, ICON_SIZE, Color)
from tajail import (myfunc, myfunc_import)
from tapalette import (block_names, value_blocks)
from tatype import (TATypeError, TYPES_NUMERIC)
from tautils import (get_pixbuf_from_journal, data_from_file, get_stack_name,
+ movie_media_type, audio_media_type, image_media_type,
text_media_type, round_int, debug_output, find_group,
get_path, image_to_base64, data_to_string, data_to_file,
get_load_name, chooser_dialog)
@@ -1081,6 +1082,7 @@ class LogoCode:
""" Get contents of URL as text or tempfile to image """
if "://" not in url: # no protocol
url = "http://" + url # assume HTTP
+
try:
req = urllib2.urlopen(url)
except urllib2.HTTPError, e:
@@ -1097,12 +1099,12 @@ class LogoCode:
self.tw.running_sugar)
raise logoerror('#noconnection')
- if req.info().getheader("Content-Type")[0:5] == "image":
- # it can't be deleted immediately, or else we won't ever access it
+ mediatype = req.info().getheader('Content-Type')
+ if mediatype[0:5] in ['image', 'audio', 'video']:
tmp = tempfile.NamedTemporaryFile(delete=False)
- tmp.write(req.read()) # prepare for writing
- tmp.flush() # actually write it
- obj = Media('media', value=tmp.name)
+ tmp.write(req.read())
+ tmp.flush()
+ obj = Media(mediatype[0:5], value=tmp.name)
return obj
else:
return req.read()
@@ -1120,19 +1122,29 @@ class LogoCode:
def show(self, obj, center=False):
""" Show is the general-purpose media-rendering block. """
- # media
+ mediatype = None
+
if isinstance(obj, Media) and obj.value:
self.filepath = None
self.pixbuf = None # Camera writes directly to pixbuf
self.dsobject = None
- # camera snapshot
if obj.value.lower() in media_blocks_dictionary:
media_blocks_dictionary[obj.value.lower()]()
- # file path
+ mediatype = 'image' # camera snapshot
elif os_path_exists(obj.value):
self.filepath = obj.value
- # datastore object
+ mediatype = obj.type
+ # If for some reason the obj.type is not set, try guessing.
+ if mediatype is None and self.filepath is not None:
+ if movie_media_type(self.filepath):
+ mediatype = 'video'
+ elif audio_media_type(self.filepath):
+ mediatype = 'audio'
+ elif image_media_type(self.filepath):
+ mediatype = 'image'
+ elif text_media_type(self.filepath):
+ mediatype = 'text'
elif self.tw.running_sugar:
from sugar.datastore import datastore
try:
@@ -1140,8 +1152,19 @@ class LogoCode:
except:
debug_output("Couldn't find dsobject %s" %
(obj.value), self.tw.running_sugar)
+
if self.dsobject is not None:
self.filepath = self.dsobject.file_path
+ if 'mime_type' in self.dsobject.metadata:
+ mimetype = self.dsobject.metadata['mime_type']
+ if mimetype[0:5] == 'video':
+ mediatype = 'video'
+ elif mimetype[0:5] == 'audio':
+ mediatype = 'audio'
+ elif mimetype[0:5] == 'image':
+ mediatype = 'image'
+ else:
+ mediatype = 'text'
if self.pixbuf is not None:
self.insert_image(center=center, pixbuf=True)
@@ -1152,36 +1175,40 @@ class LogoCode:
self.dsobject.metadata['title'])
else:
self.tw.showlabel('nojournal', obj.value)
+
debug_output("Couldn't open %s" % (obj.value),
self.tw.running_sugar)
- elif obj.type == 'media':
+ elif obj.type == 'media' or mediatype == 'image':
self.insert_image(center=center)
- elif obj.type == 'descr':
+ elif mediatype == 'audio':
+ self.play_sound()
+ elif mediatype == 'video':
+ self.play_video()
+ elif obj.type == 'descr' or mediatype == 'text':
mimetype = None
if self.dsobject is not None and \
'mime_type' in self.dsobject.metadata:
mimetype = self.dsobject.metadata['mime_type']
+
description = None
if self.dsobject is not None and \
'description' in self.dsobject.metadata:
description = self.dsobject.metadata[
'description']
+
self.insert_desc(mimetype, description)
- elif obj.type == 'audio':
- self.play_sound()
- elif obj.type == 'video':
- self.play_video()
if self.dsobject is not None:
self.dsobject.destroy()
- # text or number
- elif isinstance(obj, (basestring, float, int)):
+ elif isinstance(obj, (basestring, float, int)): # text or number
if isinstance(obj, (float, int)):
obj = round_int(obj)
+
x, y = self.x2tx(), self.y2ty()
if center:
y -= self.tw.canvas.textsize
+
self.tw.turtles.get_active_turtle().draw_text(
obj, x, y,
int(self.tw.canvas.textsize * self.scale / 100.),
diff --git a/TurtleArt/tapaletteview.py b/TurtleArt/tapaletteview.py
new file mode 100644
index 0000000..945be0f
--- /dev/null
+++ b/TurtleArt/tapaletteview.py
@@ -0,0 +1,409 @@
+# -*- coding: utf-8 -*-
+#Copyright (c) 2014, Walter Bender
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#THE SOFTWARE.
+
+_SKIN_IMAGE = 1
+_MARGIN = 5
+_BUTTON_SIZE = 32
+
+from tautils import find_group, debug_output, get_stack_width_and_height
+from tablock import Block
+from tapalette import (palette_names, palette_blocks, hidden_proto_blocks,
+ block_styles)
+from taconstants import (PALETTE_SCALE, ICON_SIZE, PYTHON_SKIN, XO1,
+ HORIZONTAL_PALETTE, PALETTE_WIDTH, PALETTE_HEIGHT,
+ CATEGORY_LAYER, TOP_LAYER, PROTO_LAYER)
+from tasprite_factory import SVG, svg_str_to_pixbuf
+from sprites import Sprite
+
+
+class PaletteView():
+ ''' Palette View class abstraction '''
+
+ def __init__(self, turtle_window, n):
+ '''
+ This class handles the display of block palettes
+ '''
+ self.blocks = []
+ self.backgrounds = [None, None]
+ self.visible = False
+ self.populated = False
+
+ self._turtle_window = turtle_window
+ self._palette_index = n
+
+ if not n < len(palette_names):
+ # Shouldn't happen, but hey...
+ debug_output('palette index %d is out of range' % n,
+ self._turtle_window.running_sugar)
+ self._name = 'undefined'
+ else:
+ self._name = palette_names[n]
+
+ def create(self, regenerate=True, show=False):
+ if not self._name == 'undefined':
+ # Create proto blocks for each palette entry
+ self._create_proto_blocks()
+
+ save_selected = self._turtle_window.selected_palette
+ self.layout(regenerate=regenerate,
+ show=(show or
+ save_selected == self._palette_index))
+
+ def show(self):
+ ''' Show palette background and proto blocks. If needed, display
+ shift button. '''
+ orientation = self._turtle_window.orientation
+ if self.backgrounds[orientation] is not None:
+ self.backgrounds[orientation].set_layer(CATEGORY_LAYER)
+
+ for blk in self.blocks:
+ if blk.get_visibility():
+ blk.spr.set_layer(PROTO_LAYER)
+ else:
+ blk.spr.hide()
+
+ self.display_palette_shift_buttons()
+
+ self.visible = True
+
+ def hide(self):
+ ''' Hide the palette. '''
+ for background in self.backgrounds:
+ if background is not None:
+ background.hide()
+
+ for blk in self.blocks:
+ blk.spr.hide()
+
+ self._hide_palette_shift_buttons()
+
+ if self._trash_palette():
+ for blk in self._turtle_window.trash_stack:
+ for gblk in find_group(blk):
+ gblk.spr.hide()
+
+ self.visible = False
+
+ def move(self, x, y):
+ ''' Move the palette. '''
+ buttons = self._turtle_window.palette_button
+
+ for blk in self.blocks:
+ blk.spr.move((x + blk.spr.save_xy[0], y + blk.spr.save_xy[1]))
+
+ for button in buttons:
+ button.move((x + button.save_xy[0], y + button.save_xy[1]))
+
+ for spr in self.backgrounds:
+ if spr is not None:
+ spr.move((x + spr.save_xy[0], y + spr.save_xy[1]))
+
+ if self._trash_palette():
+ for blk in self._turtle_window.trash_stack:
+ for gblk in find_group(blk):
+ gblk.spr.move((x + gblk.spr.save_xy[0],
+ y + gblk.spr.save_xy[1]))
+
+ def shift(self):
+ ''' Shift blocks on the palette. '''
+ buttons = self._turtle_window.palette_button
+ orientation = self._turtle_window.orientation
+
+ x, y = self.backgrounds[orientation].get_xy()
+ w, h = self.backgrounds[orientation].get_dimensions()
+ bx, by = self.blocks[0].spr.get_xy()
+ if orientation == 0:
+ width = self._turtle_window.width
+
+ if bx != _BUTTON_SIZE:
+ dx = w - width
+ else:
+ dx = width - w
+ dy = 0
+ else:
+ height = self._turtle_window.height
+ offset = self._turtle_window.toolbar_offset
+
+ dx = 0
+ if by != offset + _BUTTON_SIZE + _MARGIN:
+ dy = h - height + ICON_SIZE
+ else:
+ dy = height - h - ICON_SIZE
+
+ for blk in self.blocks:
+ if blk.get_visibility():
+ blk.spr.move_relative((dx, dy))
+
+ buttons[orientation].set_layer(TOP_LAYER)
+ if dx < 0 or dy < 0:
+ buttons[orientation + 5].set_layer(TOP_LAYER)
+ buttons[orientation + 3].hide()
+ else:
+ buttons[orientation + 5].hide()
+ buttons[orientation + 3].set_layer(TOP_LAYER)
+
+ def _create_proto_blocks(self):
+ '''
+ Create the proto blocks that will populate this palette.
+ Reload the palette, but reuse the existing blocks.
+ If a block doesn't exist, add it.
+ '''
+ for blk in self.blocks:
+ blk.spr.hide()
+
+ preexisting_blocks = self.blocks[:]
+ self.blocks = []
+ for name in palette_blocks[self._palette_index]:
+ # Did we already create this block?
+ preexisting_block = False
+ for blk in preexisting_blocks:
+ if blk.name == name:
+ self.blocks.append(blk)
+ preexisting_block = True
+ break
+
+ # If not, create it now.
+ if not preexisting_block:
+ self.blocks.append(Block(self._turtle_window.block_list,
+ self._turtle_window.sprite_list,
+ name, 0, 0, 'proto', [],
+ PALETTE_SCALE))
+ if name in hidden_proto_blocks:
+ self.blocks[-1].set_visibility(False)
+ else:
+ self.blocks[-1].spr.set_layer(PROTO_LAYER)
+ self.blocks[-1].unhighlight()
+ self.blocks[-1].resize()
+
+ # Some proto blocks get a skin.
+ if name in block_styles['box-style-media']:
+ self._proto_skin(name + 'small', self.blocks[-1].spr)
+ elif name in PYTHON_SKIN:
+ self._proto_skin('pythonsmall', self.blocks[-1].spr)
+ elif len(self.blocks[-1].spr.labels) > 0:
+ self.blocks[-1].refresh()
+
+ self.populated = True
+
+ def _proto_skin(self, name, spr):
+ ''' Utility for creating proto block skins '''
+ x, y = self._turtle_window.calc_image_offset(name, spr)
+ spr.set_image(self._turtle_window.media_shapes[name], _SKIN_IMAGE,
+ x, y)
+
+ def _float_palette(self, spr):
+ ''' We sometimes let the palette move with the canvas. '''
+ if self._turtle_window.running_sugar and \
+ not self._turtle_window.hw in [XO1]:
+ spr.move_relative(
+ (self._turtle_window.activity.hadj_value,
+ self._turtle_window.activity.vadj_value))
+
+ def _trash_palette(self):
+ return 'trash' in palette_names and \
+ self._palette_index == palette_names.index('trash')
+
+ def layout(self, regenerate=False, show=True):
+ ''' Layout prototypes in a palette. '''
+
+ offset = self._turtle_window.toolbar_offset
+ buttons = self._turtle_window.palette_button
+ orientation = self._turtle_window.orientation
+ w = PALETTE_WIDTH
+ h = PALETTE_HEIGHT
+
+ if orientation == HORIZONTAL_PALETTE:
+ x, y, max_w = self._horizontal_layout(
+ _BUTTON_SIZE, offset + _MARGIN, self.blocks)
+ if self._trash_palette():
+ blocks = [] # self.blocks[:]
+ for blk in self._turtle_window.trash_stack:
+ blocks.append(blk)
+ x, y, max_w = self._horizontal_layout(x + max_w, y, blocks)
+ w = x + max_w + _BUTTON_SIZE + _MARGIN
+ if show:
+ buttons[2].move((w - _BUTTON_SIZE, offset))
+ buttons[4].move((_BUTTON_SIZE, offset))
+ buttons[6].move((_BUTTON_SIZE, offset))
+ else:
+ x, y, max_h = self._vertical_layout(
+ _MARGIN, offset + _BUTTON_SIZE + _MARGIN, self.blocks)
+ if self._trash_palette():
+ blocks = [] # self.blocks[:]
+ for blk in self._turtle_window.trash_stack:
+ blocks.append(blk)
+ x, y, max_h = self._vertical_layout(x, y + max_h, blocks)
+ h = y + max_h + _BUTTON_SIZE + _MARGIN - offset
+ if show:
+ buttons[2].move((PALETTE_WIDTH - _BUTTON_SIZE, offset))
+ buttons[3].move((0, offset + _BUTTON_SIZE))
+ buttons[5].move((0, offset + _BUTTON_SIZE))
+
+ self._make_background(0, offset, w, h, regenerate)
+
+ if show:
+ for blk in self.blocks:
+ if blk.get_visibility():
+ blk.spr.set_layer(PROTO_LAYER)
+ else:
+ blk.spr.hide()
+
+ buttons[2].save_xy = buttons[2].get_xy()
+ self._float_palette(buttons[2])
+ self.backgrounds[orientation].set_layer(CATEGORY_LAYER)
+ self.display_palette_shift_buttons()
+
+ if self._trash_palette():
+ for blk in self._turtle_window.trash_stack:
+ for gblk in find_group(blk):
+ gblk.spr.set_layer(PROTO_LAYER)
+
+ svg = SVG()
+ self.backgrounds[orientation].set_shape(
+ svg_str_to_pixbuf(svg.palette(w, h)))
+
+ def _make_background(self, x, y, w, h, regenerate=False):
+ ''' Make the background sprite for the palette. '''
+ orientation = self._turtle_window.orientation
+
+ if regenerate and not self.backgrounds[orientation] is None:
+ self.backgrounds[orientation].hide()
+ self.backgrounds[orientation] = None
+
+ if self.backgrounds[orientation] is None:
+ svg = SVG()
+ self.backgrounds[orientation] = \
+ Sprite(self._turtle_window.sprite_list, x, y,
+ svg_str_to_pixbuf(svg.palette(w, h)))
+ self.backgrounds[orientation].save_xy = (x, y)
+
+ self._float_palette(self.backgrounds[orientation])
+
+ if orientation == 0 and w > self._turtle_window.width:
+ self.backgrounds[orientation].type = \
+ 'category-shift-horizontal'
+ elif orientation == 1 and \
+ h > self._turtle_window.height - ICON_SIZE:
+ self.backgrounds[orientation].type = \
+ 'category-shift-vertical'
+ else:
+ self.backgrounds[orientation].type = 'category'
+
+ '''
+ if self._trash_palette():
+ svg = SVG()
+ self.backgrounds[orientation].set_shape(
+ svg_str_to_pixbuf(svg.palette(w, h)))
+ '''
+
+ def _horizontal_layout(self, x, y, blocks):
+ ''' Position prototypes in a horizontal palette. '''
+ offset = self._turtle_window.toolbar_offset
+ max_w = 0
+
+ for blk in blocks:
+ if not blk.get_visibility():
+ continue
+
+ w, h = get_stack_width_and_height(blk)
+ if y + h > PALETTE_HEIGHT + offset:
+ x += int(max_w + 3)
+ y = offset + 3
+ 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)))
+ g.spr.save_xy = g.spr.get_xy()
+ self._float_palette(g.spr)
+ 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 blk in blocks:
+ if not blk.get_visibility():
+ continue
+
+ w, h = get_stack_width_and_height(blk)
+ 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))
+ g.spr.save_xy = (g.spr.save_xy[0] + dx,
+ g.spr.save_xy[1])
+ row = []
+ row_w = 0
+ x = 4
+ y += int(max_h + 3)
+ max_h = 0
+
+ row.append(blk)
+ row_w += (4 + w)
+
+ (bx, by) = blk.spr.get_xy()
+ dx = int(x - bx)
+ dy = int(y - by)
+ for g in find_group(blk):
+ g.spr.move_relative((dx, dy))
+ g.spr.save_xy = g.spr.get_xy()
+ self._float_palette(g.spr)
+
+ 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))
+ g.spr.save_xy = (g.spr.save_xy[0] + dx, g.spr.save_xy[1])
+
+ return x, y, max_h
+
+ def _hide_palette_shift_buttons(self):
+ buttons = self._turtle_window.palette_button
+ for i in range(4):
+ buttons[i + 3].hide()
+
+ def display_palette_shift_buttons(self):
+ ''' Palettes too wide (or tall) for the screen get a shift button. '''
+ self._hide_palette_shift_buttons()
+
+ buttons = self._turtle_window.palette_button
+ orientation = self._turtle_window.orientation
+
+ if self.backgrounds[orientation].type == 'category-shift-horizontal':
+ buttons[3].set_layer(CATEGORY_LAYER)
+ elif self.backgrounds[orientation].type == 'category-shift-vertical':
+ buttons[4].set_layer(CATEGORY_LAYER)
diff --git a/TurtleArt/taselector.py b/TurtleArt/taselector.py
new file mode 100644
index 0000000..5e680f4
--- /dev/null
+++ b/TurtleArt/taselector.py
@@ -0,0 +1,108 @@
+# -*- coding: utf-8 -*-
+#Copyright (c) 2014, Walter Bender
+
+#Permission is hereby granted, free of charge, to any person obtaining a copy
+#of this software and associated documentation files (the "Software"), to deal
+#in the Software without restriction, including without limitation the rights
+#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+#copies of the Software, and to permit persons to whom the Software is
+#furnished to do so, subject to the following conditions:
+
+#The above copyright notice and this permission notice shall be included in
+#all copies or substantial portions of the Software.
+
+#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+#THE SOFTWARE.
+
+import os
+
+from tautils import debug_output, error_output
+from tapalette import palette_names
+from taconstants import ICON_SIZE, CATEGORY_LAYER, TAB_LAYER
+from tasprite_factory import SVG, svg_from_file, svg_str_to_pixbuf
+from sprites import Sprite
+
+
+def create_toolbar_background(sprite_list, width):
+ # Create the toolbar background for the selectors
+ spr = Sprite(sprite_list, 0, 0,
+ svg_str_to_pixbuf(SVG().toolbar(2 * width, ICON_SIZE)))
+ spr.type = 'toolbar'
+ spr.set_layer(CATEGORY_LAYER)
+ return spr
+
+
+class Selector():
+ ''' Selector class abstraction '''
+
+ def __init__(self, turtle_window, n):
+ '''This class handles the display of palette selectors (Only relevant
+ to GNOME version and very old versions of Sugar).
+ '''
+
+ self.shapes = []
+ self.spr = None
+ self._turtle_window = turtle_window
+ self._index = n
+
+ if not n < len(palette_names):
+ # Shouldn't happen, but hey...
+ debug_output('palette index %d is out of range' % n,
+ self._turtle_window.running_sugar)
+ self._name = 'extras'
+ else:
+ self._name = palette_names[n]
+
+ icon_pathname = None
+ for path in self._turtle_window.icon_paths:
+ if os.path.exists(os.path.join(path, '%soff.svg' % (self._name))):
+ icon_pathname = os.path.join(path, '%soff.svg' % (self._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._turtle_window.icon_paths[0], 'extrasoff.svg')))
+ error_output('Unable to open %soff.svg' % (self._name),
+ self._turtle_window.running_sugar)
+
+ icon_pathname = None
+ for path in self._turtle_window.icon_paths:
+ if os.path.exists(os.path.join(path, '%son.svg' % (self._name))):
+ icon_pathname = os.path.join(path, '%son.svg' % (self._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._turtle_window.icon_paths[0], 'extrason.svg')))
+ error_output('Unable to open %son.svg' % (self._name),
+ self._turtle_window.running_sugar)
+
+ self.shapes.append(off_shape)
+ self.shapes.append(on_shape)
+
+ x = int(ICON_SIZE * self._index)
+ self.spr = Sprite(self._turtle_window.sprite_list, x, 0, off_shape)
+ self.spr.type = 'selector'
+ self.spr.name = self._name
+ self.set_layer()
+
+ def set_shape(self, i):
+ if self.spr is not None and i in [0, 1]:
+ self.spr.set_shape(self.shapes[i])
+
+ def set_layer(self, layer=TAB_LAYER):
+ if self.spr is not None:
+ self.spr.set_layer(layer)
+
+ def hide(self):
+ if self.spr is not None:
+ self.spr.hide()
diff --git a/TurtleArt/tasprite_factory.py b/TurtleArt/tasprite_factory.py
index e83ac30..21777df 100755
--- a/TurtleArt/tasprite_factory.py
+++ b/TurtleArt/tasprite_factory.py
@@ -1376,7 +1376,6 @@ def generator(datapath):
svg_str = svg.basic_block()
f.write(svg_str)
close_file(f)
- '''
svg = SVG()
f = open_file(datapath, "basic1arg.svg")
@@ -1386,10 +1385,7 @@ def generator(datapath):
svg_str = svg.basic_block()
f.write(svg_str)
close_file(f)
- print 'basic1arg.svg'
- print svg.docks
- '''
svg = SVG()
f = open_file(datapath, "basic2arg.svg")
svg.set_scale(2)
@@ -1408,7 +1404,6 @@ def generator(datapath):
f.write(svg_str)
close_file(f)
- '''
svg = SVG()
f = open_file(datapath, "box.svg")
svg.set_scale(2)
@@ -1417,10 +1412,6 @@ def generator(datapath):
f.write(svg_str)
close_file(f)
- print 'number.svg'
- print svg.docks
- '''
-
svg = SVG()
f = open_file(datapath, "media.svg")
svg.set_scale(2)
@@ -1513,6 +1504,7 @@ def generator(datapath):
svg_str = svg.clamp()
f.write(svg_str)
close_file(f)
+ '''
svg = SVG()
f = open_file(datapath, "clampn.svg")
@@ -1526,6 +1518,7 @@ def generator(datapath):
f.write(svg_str)
close_file(f)
+ '''
svg = SVG()
f = open_file(datapath, "clampe.svg")
svg.set_scale(2)
@@ -1537,6 +1530,7 @@ def generator(datapath):
svg_str = svg.clamp()
f.write(svg_str)
close_file(f)
+ '''
svg = SVG()
f = open_file(datapath, "clampb.svg")
@@ -1561,7 +1555,6 @@ def generator(datapath):
svg_str = svg.clamp_until()
f.write(svg_str)
close_file(f)
- '''
def main():
diff --git a/TurtleArt/taturtle.py b/TurtleArt/taturtle.py
index c3c7831..9845b07 100644
--- a/TurtleArt/taturtle.py
+++ b/TurtleArt/taturtle.py
@@ -28,7 +28,7 @@ import cairo
from random import uniform
from math import sin, cos, pi, sqrt
from taconstants import (TURTLE_LAYER, DEFAULT_TURTLE_COLORS, DEFAULT_TURTLE,
- Color)
+ CONSTANTS, Color, ColorObj)
from tasprite_factory import SVG, svg_str_to_pixbuf
from tacanvas import wrap100, COLOR_TABLE
from sprites import Sprite
@@ -368,9 +368,12 @@ class Turtle:
def set_color(self, color=None, share=True):
''' Set the pen color for this turtle. '''
+ if isinstance(color, ColorObj):
+ # See comment in tatype.py TYPE_BOX -> TYPE_COLOR
+ color = color.color
if color is None:
color = self._pen_color
- # Special case for color blocks
+ # Special case for color blocks from CONSTANTS
elif isinstance(color, Color):
self.set_shade(color.shade, share)
self.set_gray(color.gray, share)
diff --git a/TurtleArt/tatype.py b/TurtleArt/tatype.py
index 0fcfc3c..709a200 100644
--- a/TurtleArt/tatype.py
+++ b/TurtleArt/tatype.py
@@ -23,7 +23,7 @@
import ast
from tablock import Media
-from taconstants import (Color, CONSTANTS)
+from taconstants import (Color, ColorObj, CONSTANTS)
class Type(object):
@@ -189,6 +189,7 @@ TYPE_CONVERTERS = {
# converting A -> C must yield the same result as converting A -> B -> C.
# TYPE_OBJECT is the supertype of everything.
TYPE_BOX: {
+ TYPE_COLOR: ColorObj, # FIXME: should be Color.name
TYPE_FLOAT: float,
TYPE_INT: int,
TYPE_NUMBER: float,
diff --git a/TurtleArt/tautils.py b/TurtleArt/tautils.py
index 8e37f95..4c075ae 100644
--- a/TurtleArt/tautils.py
+++ b/TurtleArt/tautils.py
@@ -33,6 +33,7 @@ import pickle
import subprocess
import os
import string
+import mimetypes
from gettext import gettext as _
try:
@@ -483,24 +484,34 @@ def base64_to_image(data, path_name):
def movie_media_type(name):
''' Is it movie media? '''
- return name.lower().endswith(('.ogv', '.vob', '.mp4', '.wmv', '.mov',
- '.mpeg', '.ogg', '.webm'))
+ guess = mimetypes.guess_type(name)
+ if guess[0] is None:
+ return False
+ return guess[0][0:5] == 'video'
def audio_media_type(name):
''' Is it audio media? '''
- return name.lower().endswith(('.oga', '.m4a'))
+ guess = mimetypes.guess_type(name)
+ if guess[0] is None:
+ return False
+ return guess[0][0:5] == 'audio'
def image_media_type(name):
''' Is it image media? '''
- return name.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.tiff',
- '.tif', '.svg'))
+ guess = mimetypes.guess_type(name)
+ if guess[0] is None:
+ return False
+ return guess[0][0:5] == 'image'
def text_media_type(name):
''' Is it text media? '''
- return name.lower().endswith(('.txt', '.py', '.lg', '.rtf'))
+ guess = mimetypes.guess_type(name)
+ if guess[0] is None:
+ return False
+ return guess[0][0:4] == 'text'
def round_int(num):
@@ -803,6 +814,26 @@ def find_blk_below(blk, namelist):
return None
+def get_stack_width_and_height(blk):
+ ''' What are the width and height of a stack? '''
+ minx = 10000
+ miny = 10000
+ maxx = -10000
+ maxy = -10000
+ for gblk in find_group(blk):
+ (x, y) = gblk.spr.get_xy()
+ w, h = gblk.spr.get_dimensions()
+ if x < minx:
+ minx = x
+ if y < miny:
+ miny = y
+ if x + w > maxx:
+ maxx = x + w
+ if y + h > maxy:
+ maxy = y + h
+ return(maxx - minx, maxy - miny)
+
+
def get_stack_name(blk):
''' Return the name of the action stack that the given block belongs to.
If the top block of this stack is not a stack-defining block, return
diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py
index 09b9b30..d371e77 100644
--- a/TurtleArt/tawindow.py
+++ b/TurtleArt/tawindow.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
#Copyright (c) 2007, Playful Invention Company
-#Copyright (c) 2008-13, Walter Bender
+#Copyright (c) 2008-14, Walter Bender
#Copyright (c) 2009-11 Raúl Gutiérrez Segalés
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
@@ -52,20 +52,19 @@ from taconstants import (HORIZONTAL_PALETTE, VERTICAL_PALETTE, BLOCK_SCALE,
MEDIA_SHAPES, STATUS_SHAPES, OVERLAY_SHAPES,
TOOLBAR_SHAPES, TAB_LAYER, RETURN, OVERLAY_LAYER,
CATEGORY_LAYER, BLOCKS_WITH_SKIN, ICON_SIZE,
- PALETTE_SCALE, PALETTE_WIDTH, SKIN_PATHS, MACROS,
+ PALETTE_WIDTH, SKIN_PATHS, MACROS, Color, KEY_DICT,
TOP_LAYER, BLOCK_LAYER, OLD_NAMES, DEFAULT_TURTLE,
TURTLE_LAYER, EXPANDABLE, NO_IMPORT, TEMPLATES,
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, TMP_SVG_PATH, TMP_ODP_PATH,
- Color, KEY_DICT)
+ EXPANDABLE_FLOW, SUFFIX, TMP_SVG_PATH, TMP_ODP_PATH)
from tapalette import (palette_names, palette_blocks, expandable_blocks,
block_names, content_blocks, default_values,
special_names, block_styles, help_strings,
- hidden_proto_blocks, string_or_number_args,
- make_palette, palette_name_to_index,
- palette_init_on_start, palette_i18n_names)
+ string_or_number_args, make_palette,
+ palette_name_to_index, palette_init_on_start,
+ palette_i18n_names)
from talogo import (LogoCode, logoerror)
from tacanvas import TurtleGraphics
from tablock import (Blocks, Block, Media, media_blocks_dictionary)
@@ -81,8 +80,10 @@ from tautils import (magnitude, get_load_name, get_save_name, data_from_file,
error_output, find_hat, find_bot_block,
restore_clamp, collapse_clamp, data_from_string,
increment_name, get_screen_dpi)
-from tasprite_factory import (SVG, svg_str_to_pixbuf, svg_from_file)
+from tasprite_factory import (svg_str_to_pixbuf, svg_from_file)
from tapalette import block_primitives
+from tapaletteview import PaletteView
+from taselector import (Selector, create_toolbar_background)
from sprites import (Sprites, Sprite)
if _GST_AVAILABLE:
@@ -143,7 +144,7 @@ class TurtleArtWindow():
# Make sure macros_path is somewhere writable
self.macros_path = os.path.join(
os.path.expanduser('~'), 'Activities',
- 'TurtleArt.activity', _MACROS_SUBPATH)
+ os.path.basename(path), _MACROS_SUBPATH)
self._setup_events()
else:
self.interactive_mode = False
@@ -243,16 +244,13 @@ class TurtleArtWindow():
self.status_spr = None
self.status_shapes = {}
self.toolbar_spr = None
- self.palette_sprs = []
- self.palettes = []
self.palette_button = []
+ self.palette_views = []
self.trash_stack = []
self.selected_palette = None
self.previous_palette = None
self.selectors = []
self.selected_selector = None
- self.previous_selector = None
- self.selector_shapes = []
self._highlighted_blk = None
self.selected_blk = None
self.selected_spr = None
@@ -295,7 +293,7 @@ class TurtleArtWindow():
self._configure_cb(None)
- self._icon_paths = [os.path.join(self.path, 'icons')]
+ self.icon_paths = [os.path.join(self.path, 'icons')]
self.lc = LogoCode(self)
@@ -370,25 +368,30 @@ class TurtleArtWindow():
else:
return None
- def _get_plugins_from_plugins_dir(self, path):
+ def _get_plugins_from_plugins_dir(self, paths):
''' Look for plugin files in plugin dir. '''
plugin_files = []
- if path is not None:
+ for path in paths:
candidates = os.listdir(path)
candidates.sort()
for dirname in candidates:
pname = os.path.join(path, dirname, dirname + '.py')
if os.path.exists(pname):
- plugin_files.append(dirname)
+ plugin_files.append({'dirname': dirname, 'path': path})
return plugin_files
def _init_plugins(self):
''' Try importing plugin files from the plugin dir. '''
- plist = self._get_plugins_from_plugins_dir(self._get_plugin_home())
- for plugin_dir in plist:
- self.init_plugin(plugin_dir)
-
- def init_plugin(self, plugin_dir):
+ homepath = os.path.join(os.path.expanduser('~'), 'Activities',
+ os.path.basename(self.path), _PLUGIN_SUBPATH)
+ paths = [self._get_plugin_home()]
+ if paths[0] != homepath and os.path.exists(homepath):
+ paths.append(homepath)
+ plist = self._get_plugins_from_plugins_dir(paths)
+ for plugin in plist:
+ self.init_plugin(plugin['dirname'], plugin['path'])
+
+ def init_plugin(self, plugin_dir, plugin_path):
''' Initialize plugin in plugin_dir '''
plugin_class = plugin_dir.capitalize()
f = 'def f(self): from plugins.%s.%s import %s; return %s(self)' \
@@ -401,8 +404,7 @@ class TurtleArtWindow():
debug_output('Successfully importing %s' % (plugin_class),
self.running_sugar)
# Add the icon dir to the icon_theme search path
- self._add_plugin_icon_dir(os.path.join(self._get_plugin_home(),
- plugin_dir))
+ self._add_plugin_icon_dir(os.path.join(plugin_path, plugin_dir))
# Add the plugin to the list of global objects
global_objects[plugin_class] = self.turtleart_plugins[-1]
except Exception as e:
@@ -415,7 +417,7 @@ class TurtleArtWindow():
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)
+ self.icon_paths.append(icon_path)
def _get_plugin_instance(self, plugin_name):
''' Returns the plugin 'plugin_name' instance '''
@@ -770,7 +772,7 @@ class TurtleArtWindow():
''' Change icon for user-defined blocks after loading Python code. '''
if blk is not None:
if blk.name in PYTHON_SKIN:
- x, y = self._calc_image_offset('pythonon', blk.spr)
+ x, y = self.calc_image_offset('pythonon', blk.spr)
blk.set_image(self.media_shapes['pythonon'], x, y)
self._resize_skin(blk)
@@ -903,7 +905,7 @@ class TurtleArtWindow():
self.show_toolbar_palette(n)
self.palette_button[self.orientation].set_layer(TAB_LAYER)
self.palette_button[2].set_layer(TAB_LAYER)
- self._display_palette_shift_button(n)
+ self.palette_views[n].display_palette_shift_buttons()
if not self.running_sugar or not self.activity.has_toolbarbox:
self.toolbar_spr.set_layer(CATEGORY_LAYER)
self.palette = True
@@ -920,26 +922,12 @@ class TurtleArtWindow():
def move_palettes(self, x, y):
''' Move the palettes. '''
- for p in self.palettes:
- for blk in p:
- blk.spr.move((x + blk.spr.save_xy[0], y + blk.spr.save_xy[1]))
- for spr in self.palette_button:
- spr.move((x + spr.save_xy[0], y + spr.save_xy[1]))
- for p in self.palette_sprs:
- if p[0] is not None:
- p[0].move((x + p[0].save_xy[0], y + p[0].save_xy[1]))
- if p[1] is not None:
- p[1].move((x + p[1].save_xy[0], y + p[1].save_xy[1]))
+ for palette in self.palette_views:
+ palette.move(x, y)
self.status_spr.move((x + self.status_spr.save_xy[0],
y + self.status_spr.save_xy[1]))
- # To do: set save_xy for blocks in Trash
- for blk in self.trash_stack:
- for gblk in find_group(blk):
- gblk.spr.move((x + gblk.spr.save_xy[0],
- y + gblk.spr.save_xy[1]))
-
def hideblocks(self):
''' Callback from 'hide blocks' block '''
if not self.interactive_mode:
@@ -981,33 +969,8 @@ class TurtleArtWindow():
int(blocks[0].font_size[0] * pango.SCALE * self.entry_scale))
self._text_entry.modify_font(font_desc)
- def _shift_toolbar_palette(self, n):
- ''' Shift blocks on specified palette '''
- x, y = self.palette_sprs[n][self.orientation].get_xy()
- w, h = self.palette_sprs[n][self.orientation].get_dimensions()
- bx, by = self.palettes[n][0].spr.get_xy()
- if self.orientation == 0:
- if bx != _BUTTON_SIZE:
- dx = w - self.width
- else:
- dx = self.width - w
- dy = 0
- else:
- dx = 0
- if by != self.toolbar_offset + _BUTTON_SIZE + _MARGIN:
- dy = h - self.height + ICON_SIZE
- else:
- dy = self.height - h - ICON_SIZE
- for blk in self.palettes[n]:
- if blk.get_visibility():
- blk.spr.move_relative((dx, dy))
- self.palette_button[self.orientation].set_layer(TOP_LAYER)
- if dx < 0 or dy < 0:
- self.palette_button[self.orientation + 5].set_layer(TOP_LAYER)
- self.palette_button[self.orientation + 3].hide()
- else:
- self.palette_button[self.orientation + 5].hide()
- self.palette_button[self.orientation + 3].set_layer(TOP_LAYER)
+ def _has_selectors(self):
+ return not (self.running_sugar and self.activity.has_toolbarbox)
def show_toolbar_palette(self, n, init_only=False, regenerate=False,
show=True):
@@ -1020,11 +983,10 @@ class TurtleArtWindow():
self._create_the_selectors()
# Create the empty palettes that we'll then populate with prototypes.
- if self.palette_sprs == []:
+ if self.palette_views == []:
self._create_the_empty_palettes()
- # At initialization of the program, we don't actually populate
- # the palettes.
+ # At initialization of the program, we don't populate the palettes.
if init_only:
return
@@ -1038,44 +1000,20 @@ class TurtleArtWindow():
self.selected_palette = n
self.previous_palette = self.selected_palette
- # 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 show and \
- (not self.running_sugar or not self.activity.has_toolbarbox):
- self.selected_selector = self.selectors[n]
- self.selectors[n].set_shape(self.selector_shapes[n][1])
+ # Make sure all of the selectors are visible.
+ if show and self._has_selectors():
+ self.selected_selector = n
+ self.selectors[n].set_shape(1)
for i in range(len(palette_blocks)):
- self.selectors[i].set_layer(TAB_LAYER)
+ self.selectors[i].set_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(
+ if self.palette_views[n].backgrounds[self.orientation] is not None:
+ self.palette_views[n].backgrounds[self.orientation].set_layer(
CATEGORY_LAYER)
- self._display_palette_shift_button(n)
-
- # Create 'proto' blocks for each palette entry
- self._create_proto_blocks(n)
+ self.palette_views[n].display_palette_shift_buttons()
- if show or save_selected == n:
- self._layout_palette(n, regenerate=regenerate)
- else:
- self._layout_palette(n, regenerate=regenerate, show=False)
- for blk in self.palettes[n]:
- if blk.get_visibility():
- if hasattr(blk.spr, 'set_layer'):
- blk.spr.set_layer(PROTO_LAYER)
- else:
- debug_output('WARNING: block sprite is None' % (blk.name),
- self.running_sugar)
- else:
- blk.spr.hide()
- if 'trash' in palette_names and \
- n == palette_names.index('trash'):
- for blk in self.trash_stack:
- # Deprecated
- for gblk in find_group(blk):
- if gblk.status != 'collapsed':
- gblk.spr.set_layer(TAB_LAYER)
+ self.palette_views[n].create(regenerate=regenerate, show=show)
if not show:
if not save_selected == n:
@@ -1085,10 +1023,9 @@ class TurtleArtWindow():
def regenerate_palette(self, n):
''' Regenerate palette (used by some plugins) '''
- if (not self.running_sugar or not self.activity.has_toolbarbox) and \
- self.selectors == []:
+ if self._has_selectors() and self.selectors == []:
return
- if self.palette_sprs == []:
+ if self.palette_views == []:
return
save_selected = self.selected_palette
@@ -1096,98 +1033,29 @@ class TurtleArtWindow():
self.selected_palette = n
self.previous_palette = self.selected_palette
- if save_selected == n:
- self._layout_palette(n, regenerate=True)
- else:
- self._layout_palette(n, regenerate=True, show=False)
-
- for blk in self.palettes[n]:
- if blk.get_visibility():
- if hasattr(blk.spr, 'set_layer'):
- blk.spr.set_layer(PROTO_LAYER)
- else:
- debug_output('WARNING: block sprite is None' % (blk.name),
- self.running_sugar)
- else:
- blk.spr.hide()
+ self.palette_views[n].layout(regenerate=True,
+ show=(save_selected == n))
if not save_selected == n:
self._hide_previous_palette(palette=n)
self.selected_palette = save_selected
self.previous_palette = save_previous
- def _display_palette_shift_button(self, n):
- ''' Palettes too wide (or tall) for the screen get a shift button '''
- for i in range(4):
- self.palette_button[i + 3].hide()
- if self.palette_sprs[n][self.orientation].type == \
- 'category-shift-horizontal':
- self.palette_button[3].set_layer(CATEGORY_LAYER)
- elif self.palette_sprs[n][self.orientation].type == \
- 'category-shift-vertical':
- self.palette_button[4].set_layer(CATEGORY_LAYER)
-
def _create_the_selectors(self):
''' Create the palette selector buttons: only when running
old-style Sugar toolbars or from GNOME '''
- svg = SVG()
- if self.running_sugar:
- x, y = 50, 0 # positioned at the left, top
- else:
- x, y = 0, 0
- 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
+ for i in range(len(palette_names)):
+ self.selectors.append(Selector(self, i))
# 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(2 * self.width,
- ICON_SIZE)))
- self.toolbar_spr.type = 'toolbar'
- self.toolbar_spr.set_layer(CATEGORY_LAYER)
+ self.toolbar_spr = create_toolbar_background(self.sprite_list,
+ self.width)
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])
+ for i in range(len(palette_names)):
+ self.palette_views.append(PaletteView(self, i))
# Create the palette orientation button
self.palette_button.append(
@@ -1264,56 +1132,6 @@ class TurtleArtWindow():
self.palette_button[3 + i].type = 'palette'
self.palette_button[3 + i].hide()
- def _create_proto_blocks(self, n):
- ''' Create the protoblocks that will populate a palette. '''
- # Reload the palette, but reuse the existing blocks
- # If a block doesn't exist, add it
-
- if not n < len(self.palettes):
- debug_output(
- '_create_proto_blocks: palette index %d is out of range' %
- (n), self.running_sugar)
- return
-
- for blk in self.palettes[n]:
- blk.spr.hide()
- old_blocks = self.palettes[n][:]
- self.palettes[n] = []
- for name in palette_blocks[n]:
- found_block = False
- for oblk in old_blocks:
- if oblk.name == name:
- self.palettes[n].append(oblk)
- found_block = True
- break
- if not found_block:
- self.palettes[n].append(
- Block(self.block_list, self.sprite_list, name, 0, 0,
- 'proto', [], PALETTE_SCALE))
- if name in hidden_proto_blocks:
- self.palettes[n][-1].set_visibility(False)
- else:
- if hasattr(self.palettes[n][-1].spr, 'set_layer'):
- self.palettes[n][-1].spr.set_layer(PROTO_LAYER)
- self.palettes[n][-1].unhighlight()
- else:
- debug_output('WARNING: block sprite is None' %
- (self.palettes[n][-1].name),
- self.running_sugar)
-
- # Some proto blocks get a skin.
- if name in block_styles['box-style-media']:
- self._proto_skin(name + 'small', n, -1)
- elif name[:8] == 'template': # Deprecated
- self._proto_skin(name[8:], n, -1)
- elif name[:7] == 'picture': # Deprecated
- self._proto_skin(name[7:], n, -1)
- elif name in PYTHON_SKIN:
- self._proto_skin('pythonsmall', n, -1)
- if len(self.palettes[n][-1].spr.labels) > 0:
- self.palettes[n][-1].refresh()
- return
-
def _hide_toolbar_palette(self):
''' Hide the toolbar palettes '''
self._hide_previous_palette()
@@ -1332,171 +1150,13 @@ class TurtleArtWindow():
palette = self.previous_palette
# Hide previously selected palette
if palette is not None:
- if not palette < len(self.palettes):
- debug_output(
- '_hide_previous_palette: index %d is out of range' %
- (palette), self.running_sugar)
- return
- for proto in self.palettes[palette]:
- proto.spr.hide()
- if self.palette_sprs[palette][self.orientation] is not None:
- self.palette_sprs[palette][self.orientation].hide()
- if not self.running_sugar or not self.activity.has_toolbarbox:
- self.selectors[palette].set_shape(
- self.selector_shapes[palette][0])
+ self.palette_views[palette].hide()
+ if self._has_selectors():
+ self.selectors[palette].set_shape(0)
elif palette is not None and palette != self.selected_palette \
and not self.activity.has_toolbarbox:
self.activity.palette_buttons[palette].set_icon(
palette_names[palette] + 'off')
- if 'trash' in palette_names and \
- 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
- for blk in blocks:
- if not blk.get_visibility():
- continue
- 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
- for g in find_group(blk):
- g.spr.move_relative((int(dx), int(dy)))
- g.spr.save_xy = g.spr.get_xy()
- if self.running_sugar and not self.hw in [XO1]:
- g.spr.move_relative((self.activity.hadj_value,
- self.activity.vadj_value))
- 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 blk in blocks:
- if not blk.get_visibility():
- continue
- w, h = self._width_and_height(blk)
- 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))
- g.spr.save_xy = (g.spr.save_xy[0] + dx,
- g.spr.save_xy[1])
- row = []
- row_w = 0
- x = 4
- y += int(max_h + 3)
- max_h = 0
- row.append(blk)
- row_w += (4 + w)
- (bx, by) = blk.spr.get_xy()
- dx = int(x - bx)
- dy = int(y - by)
- for g in find_group(blk):
- g.spr.move_relative((dx, dy))
- g.spr.save_xy = g.spr.get_xy()
- if self.running_sugar and not self.hw in [XO1]:
- g.spr.move_relative((self.activity.hadj_value,
- self.activity.vadj_value))
- 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))
- g.spr.save_xy = (g.spr.save_xy[0] + dx, g.spr.save_xy[1])
- return x, y, max_h
-
- def _layout_palette(self, n, regenerate=False, show=True):
- ''' Layout prototypes in a palette. '''
- if n is not None:
- if self.orientation == HORIZONTAL_PALETTE:
- x, y = _BUTTON_SIZE, self.toolbar_offset + _MARGIN
- x, y, max_w = self._horizontal_layout(x, y, self.palettes[n])
- if 'trash' in palette_names and \
- n == palette_names.index('trash'):
- x, y, max_w = self._horizontal_layout(x + max_w, y,
- self.trash_stack)
- w = x + max_w + _BUTTON_SIZE + _MARGIN
- self._make_palette_spr(n, 0, self.toolbar_offset,
- w, PALETTE_HEIGHT, regenerate)
- if show:
- self.palette_button[2].move(
- (w - _BUTTON_SIZE, self.toolbar_offset))
- self.palette_button[4].move(
- (_BUTTON_SIZE, self.toolbar_offset))
- self.palette_button[6].move(
- (_BUTTON_SIZE, self.toolbar_offset))
- else:
- x, y = _MARGIN, self.toolbar_offset + _BUTTON_SIZE + _MARGIN
- x, y, max_h = self._vertical_layout(x, y, self.palettes[n])
- if 'trash' in palette_names and \
- n == palette_names.index('trash'):
- x, y, max_h = self._vertical_layout(x, y + max_h,
- self.trash_stack)
- h = y + max_h + _BUTTON_SIZE + _MARGIN - self.toolbar_offset
- self._make_palette_spr(n, 0, self.toolbar_offset,
- PALETTE_WIDTH, h, regenerate)
- if show:
- self.palette_button[2].move((PALETTE_WIDTH - _BUTTON_SIZE,
- self.toolbar_offset))
- self.palette_button[3].move(
- (0, self.toolbar_offset + _BUTTON_SIZE))
- self.palette_button[5].move(
- (0, self.toolbar_offset + _BUTTON_SIZE))
- if show:
- self.palette_button[2].save_xy = \
- self.palette_button[2].get_xy()
- if self.running_sugar and not self.hw in [XO1]:
- self.palette_button[2].move_relative(
- (self.activity.hadj_value, self.activity.vadj_value))
- self.palette_sprs[n][self.orientation].set_layer(
- CATEGORY_LAYER)
- self._display_palette_shift_button(n)
-
- 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].save_xy = (x, y)
- if self.running_sugar and not self.hw in [XO1]:
- self.palette_sprs[n][self.orientation].move_relative(
- (self.activity.hadj_value, self.activity.vadj_value))
- if self.orientation == 0 and w > self.width:
- self.palette_sprs[n][self.orientation].type = \
- 'category-shift-horizontal'
- elif self.orientation == 1 and h > self.height - ICON_SIZE:
- self.palette_sprs[n][self.orientation].type = \
- 'category-shift-vertical'
- else:
- self.palette_sprs[n][self.orientation].type = 'category'
- if 'trash' in palette_names and \
- 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 '''
@@ -1543,8 +1203,9 @@ class TurtleArtWindow():
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 program'))
+ label=_('Please hit the Stop Button '
+ 'before making changes to your '
+ 'program'))
self._autohide_shape = True
return True
@@ -1859,10 +1520,10 @@ before making changes to your program'))
return
i = palette_names.index('myblocks')
palette_blocks[i].remove(blk.name)
- for pblk in self.palettes[i]:
+ for pblk in self.palette_views[i].blocks:
if pblk.name == blk.name:
pblk.spr.hide()
- self.palettes[i].remove(pblk)
+ self.palette_views[i].blocks.remove(pblk)
break
self.show_toolbar_palette(i, regenerate=True)
@@ -1896,7 +1557,7 @@ before making changes to your program'))
i = 0
if not self.running_sugar or \
not self.activity.has_toolbarbox:
- self._select_category(self.selectors[i])
+ self._select_category(self.selectors[i].spr)
else:
if self.selected_palette is not None and \
not self.activity.has_toolbarbox:
@@ -1912,7 +1573,7 @@ before making changes to your program'))
palette_names[i] + 'on')
self.show_palette(i)
elif spr.name == _('shift'):
- self._shift_toolbar_palette(self.selected_palette)
+ self.palette_views[self.selected_palette].shift()
else:
self.set_orientation(1 - self.orientation)
elif spr.type == 'toolbar':
@@ -1923,10 +1584,11 @@ before making changes to your program'))
self.orientation = orientation
self.palette_button[self.orientation].set_layer(TAB_LAYER)
self.palette_button[1 - self.orientation].hide()
- spr = self.palette_sprs[self.selected_palette][1 - self.orientation]
+ o = 1 - self.orientation
+ spr = self.palette_views[self.selected_palette].backgrounds[o]
if spr is not None:
spr.hide()
- self._layout_palette(self.selected_palette)
+ self.palette_views[self.selected_palette].layout()
self.show_palette(self.selected_palette)
def _update_action_names(self, name):
@@ -2017,7 +1679,7 @@ before making changes to your program'))
block_names[new] = name
i = palette_name_to_index(palette)
- for blk in self.palettes[i]:
+ for blk in self.palette_views[i].blocks:
if blk.name == old:
blk.name = new
blk.spr.labels[label] = name
@@ -2069,16 +1731,15 @@ before making changes to your program'))
def _select_category(self, spr):
''' Select a category from the toolbar '''
- i = self.selectors.index(spr)
- spr.set_shape(self.selector_shapes[i][1])
- if self.selected_selector is not None:
- j = self.selectors.index(self.selected_selector)
- if i == j:
- return
- self.selected_selector.set_shape(self.selector_shapes[j][0])
- self.previous_selector = self.selected_selector
- self.selected_selector = spr
- self.show_palette(i)
+ for i, selector in enumerate(self.selectors):
+ if selector.spr == spr:
+ break
+ self.selectors[i].set_shape(1)
+
+ if i != self.selected_selector:
+ self.selectors[self.selected_selector].set_shape(0)
+ self.selected_selector = i
+ self.show_palette(i)
def _select_toolbar_button(self, spr):
''' Select a toolbar button (Used when not running Sugar). '''
@@ -2169,10 +1830,10 @@ before making changes to your program'))
i = palette_name_to_index('blocks')
if name in palette_blocks[i]:
palette_blocks[i].remove(name)
- for blk in self.palettes[i]:
+ for blk in self.palette_views[i].blocks:
if blk.name == name:
blk.spr.hide()
- self.palettes[i].remove(blk)
+ self.palette_views[i].blocks.remove(blk)
self.show_toolbar_palette(i, regenerate=True)
if name in block_styles[style]:
block_styles[style].remove(name)
@@ -2249,10 +1910,11 @@ before making changes to your program'))
def _in_the_trash(self, x, y):
''' Is x, y over a palette? '''
- if self.selected_palette is not None and \
- self.palette_sprs[self.selected_palette][self.orientation]\
- .hit((x, y)):
- return True
+ n = self.selected_palette
+ if n is not None:
+ spr = self.palette_views[n].backgrounds[self.orientation]
+ if spr.hit((x, y)):
+ return True
return False
def _block_pressed(self, x, y, blk):
@@ -3687,7 +3349,7 @@ before making changes to your program'))
else:
blk.name = 'description'
if pixbuf is not None:
- x, y = self._calc_image_offset('', blk.spr)
+ x, y = self.calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
self._resize_skin(blk)
@@ -3725,7 +3387,7 @@ before making changes to your program'))
print 'selected palette is None'
return True
else:
- p = self.palettes[self.selected_palette]
+ p = self.palette_views[self.selected_palette].blocks
i = 0
if self._highlighted_blk is not None:
self._highlighted_blk.unhighlight()
@@ -4320,7 +3982,7 @@ before making changes to your program'))
w, h, = calc_image_size(blk.spr)
pixbuf = get_pixbuf_from_journal(dsobject, w, h)
if pixbuf is not None:
- x, y = self._calc_image_offset('', blk.spr)
+ x, y = self.calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
else:
self._block_skin('journalon', blk)
@@ -4330,7 +3992,7 @@ before making changes to your program'))
w, h, = calc_image_size(blk.spr)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
blk.values[0], w, h)
- x, y = self._calc_image_offset('', blk.spr)
+ x, y = self.calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
except:
debug_output('Could not open dsobject (%s)' %
@@ -4342,7 +4004,7 @@ before making changes to your program'))
w, h, = calc_image_size(blk.spr)
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(
blk.values[0], w, h)
- x, y = self._calc_image_offset('', blk.spr)
+ x, y = self.calc_image_offset('', blk.spr)
blk.set_image(pixbuf, x, y)
except:
self._block_skin('journaloff', blk)
@@ -4720,7 +4382,7 @@ before making changes to your program'))
if '.odp' not in name:
name = name + '.odp'
if name is not None:
- res = subprocess.check_output(
+ subprocess.check_output(
['cp', TMP_ODP_PATH, os.path.join(datapath, name)])
@@ -4916,7 +4578,7 @@ before making changes to your program'))
# Utilities related to putting a image 'skin' on a block
- def _calc_image_offset(self, name, spr, iw=0, ih=0):
+ def calc_image_offset(self, name, spr, iw=0, ih=0):
''' Calculate the postion for placing an image onto a sprite. '''
_l, _t = spr.label_left_top()
if name == '':
@@ -4947,12 +4609,14 @@ before making changes to your program'))
def _proto_skin(self, name, n, i):
''' Utility for calculating proto skin images '''
- x, y = self._calc_image_offset(name, self.palettes[n][i].spr)
- self.palettes[n][i].spr.set_image(self.media_shapes[name], 1, x, y)
+ x, y = self.calc_image_offset(name,
+ self.palette_views[n].blocks[i].spr)
+ self.palette_views[n].blocks[i].spr.set_image(
+ self.media_shapes[name], 1, x, y)
def _block_skin(self, name, blk):
''' Some blocks get a skin '''
- x, y = self._calc_image_offset(name, blk.spr)
+ x, y = self.calc_image_offset(name, blk.spr)
blk.set_image(self.media_shapes[name], x, y)
self._resize_skin(blk)
@@ -4960,19 +4624,19 @@ before making changes to your program'))
''' Resize the 'skin' when block scale changes. '''
if blk.name in PYTHON_SKIN:
w, h = self._calc_w_h('pythonoff', blk.spr)
- x, y = self._calc_image_offset('pythonoff', blk.spr, w, h)
+ x, y = self.calc_image_offset('pythonoff', blk.spr, w, h)
elif blk.name == 'journal':
if len(blk.values) == 1 and blk.values[0] is not None:
w, h = self._calc_w_h('', blk.spr)
- x, y = self._calc_image_offset('journaloff', blk.spr, w, h)
+ x, y = self.calc_image_offset('journaloff', blk.spr, w, h)
else:
w, h = self._calc_w_h('journaloff', blk.spr)
- x, y = self._calc_image_offset('journaloff', blk.spr, w, h)
+ x, y = self.calc_image_offset('journaloff', blk.spr, w, h)
else:
# w, h = self._calc_w_h('descriptionoff', blk.spr)
w, h = self._calc_w_h('', blk.spr)
- # x, y = self._calc_image_offset('descriptionoff', blk.spr, w, h)
- x, y = self._calc_image_offset('', blk.spr, w, h)
+ # x, y = self.calc_image_offset('descriptionoff', blk.spr, w, h)
+ x, y = self.calc_image_offset('', blk.spr, w, h)
blk.scale_image(x, y, w, h)
def _find_proto_name(self, name, label, palette='blocks'):
@@ -4984,7 +4648,7 @@ before making changes to your program'))
if isinstance(label, unicode):
label = label.encode('utf-8')
i = palette_name_to_index(palette)
- for blk in self.palettes[i]:
+ for blk in self.palette_views[i].blocks:
blk_label = blk.spr.labels[0]
if isinstance(blk.name, unicode):
blk.name = blk.name.encode('utf-8')
diff --git a/turtleblocks.py b/turtleblocks.py
index 3483169..fa324ce 100755
--- a/turtleblocks.py
+++ b/turtleblocks.py
@@ -243,8 +243,7 @@ return %s(self)" % (p, P, P)
if hasattr(self, 'client'):
if self.client.get_int(self._HOVER_HELP) == 1:
- self.hover.set_active(False)
- self._do_hover_help_off_cb(None)
+ self._do_hover_help_off_cb()
if not self.client.get_int(self._COORDINATE_SCALE) in [0, 1]:
self.tw.coord_scale = 1
else:
@@ -748,22 +747,18 @@ Would you like to save before quitting?'))
''' Toggle hover help on/off '''
self.tw.no_help = not self.tw.no_help
if self.tw.no_help:
- self._do_hover_help_off_cb(None)
+ self._do_hover_help_off_cb()
else:
- self._do_hover_help_on_cb(None)
+ self._do_hover_help_on_cb()
- def _do_hover_help_on_cb(self, button):
+ def _do_hover_help_on_cb(self):
''' Turn hover help on '''
- self.tw.no_help = False
self.hover.set_active(True)
if hasattr(self, 'client'):
self.client.set_int(self._HOVER_HELP, 0)
- def _do_hover_help_off_cb(self, button):
+ def _do_hover_help_off_cb(self):
''' Turn hover help off '''
- if self.tw.no_help: # Debounce
- return
- self.tw.no_help = True
self.tw.last_label = None
if self.tw.status_spr is not None:
self.tw.status_spr.hide()