Web · Wiki · Activities · Blog · Lists · Chat · Meeting · Bugs · Git · Translate · Archive · People · Donate
c2937d9 by Walter Bender at 2010-08-12 1
# -*- coding: utf-8 -*-
2
#Copyright (c) 2007, Playful Invention Company
383de1d by Walter Bender at 2013-01-17 3
#Copyright (c) 2008-13, Walter Bender
b0ef86c by Walter Bender at 2011-02-12 4
#Copyright (c) 2009-11 Raúl Gutiérrez Segalés
9905da9 by Raul Gutierrez Segales at 2011-01-25 5
#Copyright (c) 2011 Collabora Ltd. <http://www.collabora.co.uk/>
c2937d9 by Walter Bender at 2010-08-12 6
7
#Permission is hereby granted, free of charge, to any person obtaining a copy
8
#of this software and associated documentation files (the "Software"), to deal
9
#in the Software without restriction, including without limitation the rights
10
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
#copies of the Software, and to permit persons to whom the Software is
12
#furnished to do so, subject to the following conditions:
13
14
#The above copyright notice and this permission notice shall be included in
15
#all copies or substantial portions of the Software.
16
17
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
#THE SOFTWARE.
24
25
import pygtk
26
pygtk.require('2.0')
27
import gtk
28
import gobject
c83fa3c by Walter Bender at 2012-10-25 29
import pango
2ef9a33 by Walter Bender at 2012-10-26 30
import pangocairo
b99d698 by Walter Bender at 2012-07-12 31
8ba5716 by Walter Bender at 2011-04-13 32
from gettext import gettext as _
bcb715f by Walter Bender at 2011-02-15 33
34
try:
35
    import gst
11333ce by Walter Bender at 2013-05-22 36
    _GST_AVAILABLE = True
bcb715f by Walter Bender at 2011-02-15 37
except ImportError:
38
    # Turtle Art should not fail if gst is not available
11333ce by Walter Bender at 2013-05-22 39
    _GST_AVAILABLE = False
bcb715f by Walter Bender at 2011-02-15 40
c2937d9 by Walter Bender at 2010-08-12 41
import os
f00e3fe by Walter Bender at 2012-04-08 42
import subprocess
f2ea57b by Walter Bender at 2013-05-06 43
import errno
fc6b9cb by Walter Bender at 2010-12-02 44
f2ea57b by Walter Bender at 2013-05-06 45
from random import uniform
c2937d9 by Walter Bender at 2010-08-12 46
from math import atan2, pi
dcd7408 by Walter Bender at 2010-10-10 47
DEGTOR = 2 * pi / 360
5acdeb5 by Walter Bender at 2010-09-28 48
49
import locale
c2937d9 by Walter Bender at 2010-08-12 50
7eb786c by Walter Bender at 2012-12-23 51
from taconstants import (HORIZONTAL_PALETTE, VERTICAL_PALETTE, BLOCK_SCALE,
4fff361 by Walter Bender at 2013-05-22 52
                         MEDIA_SHAPES, STATUS_SHAPES, OVERLAY_SHAPES,
53
                         TOOLBAR_SHAPES, TAB_LAYER, RETURN, OVERLAY_LAYER,
54
                         CATEGORY_LAYER, BLOCKS_WITH_SKIN, ICON_SIZE,
55
                         PALETTE_SCALE, PALETTE_WIDTH, SKIN_PATHS, MACROS,
56
                         TOP_LAYER, BLOCK_LAYER, OLD_NAMES, DEFAULT_TURTLE,
57
                         TURTLE_LAYER, EXPANDABLE, NO_IMPORT, TEMPLATES,
58
                         PYTHON_SKIN, PALETTE_HEIGHT, STATUS_LAYER, OLD_DOCK,
59
                         EXPANDABLE_ARGS, XO1, XO15, XO175, XO30, XO4, TITLEXY,
60
                         CONTENT_ARGS, CONSTANTS, EXPAND_SKIN, PROTO_LAYER,
0ee623d by Walter Bender at 2013-07-23 61
                         EXPANDABLE_FLOW, SUFFIX, TMP_SVG_PATH)
7eb786c by Walter Bender at 2012-12-23 62
from tapalette import (palette_names, palette_blocks, expandable_blocks,
4fff361 by Walter Bender at 2013-05-22 63
                       block_names, content_blocks, default_values,
64
                       special_names, block_styles, help_strings,
65
                       hidden_proto_blocks, string_or_number_args,
66
                       make_palette, palette_name_to_index,
67
                       palette_init_on_start)
b285375 by Walter Bender at 2013-02-10 68
from talogo import (LogoCode, primitive_dictionary, logoerror)
c2937d9 by Walter Bender at 2010-08-12 69
from tacanvas import TurtleGraphics
b285375 by Walter Bender at 2013-02-10 70
from tablock import (Blocks, Block)
71
from taturtle import (Turtles, Turtle)
7eb786c by Walter Bender at 2012-12-23 72
from tautils import (magnitude, get_load_name, get_save_name, data_from_file,
4fff361 by Walter Bender at 2013-05-22 73
                     data_to_file, round_int, get_id, get_pixbuf_from_journal,
74
                     movie_media_type, audio_media_type, image_media_type,
75
                     save_picture, calc_image_size, get_path, hide_button_hit,
daaeb35 by Walter Bender at 2013-05-24 76
                     show_button_hit, chooser_dialog, arithmetic_check, xy,
4fff361 by Walter Bender at 2013-05-22 77
                     find_block_to_run, find_top_block, journal_check,
78
                     find_group, find_blk_below, data_to_string,
79
                     find_start_stack, get_hardware, debug_output,
80
                     error_output, convert, find_hat, find_bot_block,
81
                     restore_clamp, collapse_clamp, data_from_string,
82
                     increment_name, get_screen_dpi)
b285375 by Walter Bender at 2013-02-10 83
from tasprite_factory import (SVG, svg_str_to_pixbuf, svg_from_file)
84
from sprites import (Sprites, Sprite)
fc6b9cb by Walter Bender at 2010-12-02 85
11333ce by Walter Bender at 2013-05-22 86
if _GST_AVAILABLE:
bcb715f by Walter Bender at 2011-02-15 87
    from tagplay import stop_media
88
11333ce by Walter Bender at 2013-05-22 89
_MOTION_THRESHOLD = 6
90
_SNAP_THRESHOLD = 200
91
_NO_DOCK = (100, 100)  # Blocks cannot be docked
92
_BUTTON_SIZE = 32
93
_MARGIN = 5
4fff361 by Walter Bender at 2013-05-22 94
_UNFULLSCREEN_VISIBILITY_TIMEOUT = 2
11333ce by Walter Bender at 2013-05-22 95
_PLUGIN_SUBPATH = 'plugins'
96
_MACROS_SUBPATH = 'macros'
dcd7408 by Walter Bender at 2010-10-10 97
5b3215c by Walter Bender at 2012-03-26 98
c2937d9 by Walter Bender at 2010-08-12 99
class TurtleArtWindow():
2fee6e6 by Walter Bender at 2012-06-23 100
    ''' TurtleArt Window class abstraction  '''
c2937d9 by Walter Bender at 2010-08-12 101
e608481 by Marion at 2013-06-19 102
    def __init__(self, canvas_window, path, parent=None, activity=None,
d83cb4e by Walter Bender at 2012-10-19 103
                 mycolors=None, mynick=None, turtle_canvas=None,
aca7f3c by Marion at 2013-07-03 104
                 running_sugar=True, running_turtleart=True):
bc09b50 by Walter Bender at 2013-08-21 105
        '''
106
        parent: the GTK Window that TA runs in
107
        activity: the object that instantiated this TurtleArtWindow (in
108
                  GNOME, a TurtleMain instance, in Sugar, the Activity
109
                  instance)
110
        running_turtleart: are we running TA or exported python code?
2aa89e8 by Walter Bender at 2013-06-26 111
        '''
c2937d9 by Walter Bender at 2010-08-12 112
        self.parent = parent
ef080ed by Walter Bender at 2011-10-30 113
        self.turtle_canvas = turtle_canvas
11333ce by Walter Bender at 2013-05-22 114
        self._loaded_project = ''
115
        self._sharing = False
116
        self._timeout_tag = [0]
f823515 by Walter Bender at 2011-02-02 117
        self.send_event = None  # method to send events over the network
11333ce by Walter Bender at 2013-05-22 118
        self.gst_available = _GST_AVAILABLE
d83cb4e by Walter Bender at 2012-10-19 119
        self.running_sugar = False
6bcc4e9 by Walter Bender at 2013-01-16 120
        self.nick = None
aca7f3c by Marion at 2013-07-03 121
        self.running_turtleart = running_turtleart
530ac92 by Walter Bender at 2013-05-05 122
        if isinstance(canvas_window, gtk.DrawingArea):
c2937d9 by Walter Bender at 2010-08-12 123
            self.interactive_mode = True
cfe8338 by Walter Bender at 2011-10-03 124
            self.window = canvas_window
c2937d9 by Walter Bender at 2010-08-12 125
            self.window.set_flags(gtk.CAN_FOCUS)
8ba5716 by Walter Bender at 2011-04-13 126
            self.window.show_all()
d83cb4e by Walter Bender at 2012-10-19 127
            if running_sugar:
c2937d9 by Walter Bender at 2010-08-12 128
                self.parent.show_all()
129
                self.running_sugar = True
2467422 by Walter Bender at 2013-05-09 130
d83cb4e by Walter Bender at 2012-10-19 131
                from sugar import profile
2467422 by Walter Bender at 2013-05-09 132
d83cb4e by Walter Bender at 2012-10-19 133
                self.nick = profile.get_nick_name()
0a45669 by Walter Bender at 2013-05-06 134
                self.macros_path = os.path.join(
11333ce by Walter Bender at 2013-05-22 135
                    get_path(parent, 'data'), _MACROS_SUBPATH)
0a45669 by Walter Bender at 2013-05-06 136
            else:
26bd420 by Walter Bender at 2013-05-07 137
                # Make sure macros_path is somewhere writable
138
                self.macros_path = os.path.join(
139
                    os.path.expanduser('~'), 'Activities',
11333ce by Walter Bender at 2013-05-22 140
                    'TurtleArt.activity', _MACROS_SUBPATH)
c2937d9 by Walter Bender at 2010-08-12 141
            self._setup_events()
09812f9 by Walter Bender at 2011-11-05 142
        else:
c2937d9 by Walter Bender at 2010-08-12 143
            self.interactive_mode = False
cfe8338 by Walter Bender at 2011-10-03 144
            self.window = canvas_window
c2937d9 by Walter Bender at 2010-08-12 145
            self.running_sugar = False
4fededf by Walter Bender at 2013-06-21 146
147
        if activity is not None:
148
            self.activity = activity
149
        else:
150
            self.activity = parent
c2937d9 by Walter Bender at 2010-08-12 151
aca7f3c by Marion at 2013-07-03 152
        # loading and saving
c2937d9 by Walter Bender at 2010-08-12 153
        self.path = path
154
        self.load_save_folder = os.path.join(path, 'samples')
3a39272 by Walter Bender at 2010-11-16 155
        self.py_load_save_folder = os.path.join(path, 'pysamples')
a235d73 by Walter Bender at 2012-07-19 156
        self._py_cache = {}
72eb008 by Walter Bender at 2011-10-19 157
        self.used_block_list = []  # Which blocks has the user used?
c2937d9 by Walter Bender at 2010-08-12 158
        self.save_folder = None
159
        self.save_file_name = None
aca7f3c by Marion at 2013-07-03 160
        
161
        # dimensions
c2937d9 by Walter Bender at 2010-08-12 162
        self.width = gtk.gdk.screen_width()
dcd7408 by Walter Bender at 2010-10-10 163
        self.height = gtk.gdk.screen_height()
27dd7f8 by Walter Bender at 2010-08-18 164
        self.rect = gtk.gdk.Rectangle(0, 0, 0, 0)
c2937d9 by Walter Bender at 2010-08-12 165
69d7ba3 by Walter Bender at 2012-03-23 166
        self.no_help = False
1742992 by Walter Bender at 2012-03-23 167
        self.last_label = None
8d09405 by Walter Bender at 2012-10-19 168
        self._autohide_shape = True
dce9973 by Walter Bender at 2010-09-28 169
        self.keypress = ''
c2937d9 by Walter Bender at 2010-08-12 170
        self.keyvalue = 0
e8f85f0 by Walter Bender at 2012-10-24 171
        self._focus_out_id = None
1cd797e by Walter Bender at 2012-11-27 172
        self._insert_text_id = None
e8f85f0 by Walter Bender at 2012-10-24 173
        self._text_to_check = False
c2937d9 by Walter Bender at 2010-08-12 174
        self.mouse_flag = 0
175
        self.mouse_x = 0
176
        self.mouse_y = 0
f5a2055 by Walter Bender at 2013-03-01 177
        self.update_counter = 0
8c22cc8 by Walter Bender at 2012-06-02 178
        self.running_blocks = False
6553d94 by Walter Bender at 2013-05-08 179
        self.saving_blocks = False
180
        self.copying_blocks = False
181
        self.sharing_blocks = False
2467422 by Walter Bender at 2013-05-09 182
        self.deleting_blocks = False
c2937d9 by Walter Bender at 2010-08-12 183
aca7f3c by Marion at 2013-07-03 184
        # find out which character to use as decimal point
d818453 by Raul Gutierrez Segales at 2011-02-14 185
        try:
186
            locale.setlocale(locale.LC_NUMERIC, '')
36dea4b by Walter Bender at 2011-02-15 187
        except locale.Error:
7f56a04 by Walter Bender at 2011-02-22 188
            debug_output('unsupported locale', self.running_sugar)
5acdeb5 by Walter Bender at 2010-09-28 189
        self.decimal_point = locale.localeconv()['decimal_point']
dce9973 by Walter Bender at 2010-09-28 190
        if self.decimal_point == '' or self.decimal_point is None:
191
            self.decimal_point = '.'
5acdeb5 by Walter Bender at 2010-09-28 192
aca7f3c by Marion at 2013-07-03 193
        # settings that depend on the hardware
c2937d9 by Walter Bender at 2010-08-12 194
        self.orientation = HORIZONTAL_PALETTE
554d6fd by Walter Bender at 2010-10-28 195
        self.hw = get_hardware()
8d4816b by Walter Bender at 2011-11-05 196
        self.lead = 1.0
7eb786c by Walter Bender at 2012-12-23 197
        if self.hw in (XO1, XO15, XO175, XO4):
54f85f2 by Walter Bender at 2012-10-30 198
            self.scale = 1.0
199
            self.entry_scale = 0.67
f1b1a77 by Walter Bender at 2010-12-17 200
            if self.hw == XO1:
201
                self.color_mode = '565'
202
            else:
203
                self.color_mode = '888'
4b1f02e by Walter Bender at 2011-03-05 204
            if self.running_sugar and not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 205
                self.orientation = VERTICAL_PALETTE
206
        else:
a7a87c7 by Walter Bender at 2011-11-07 207
            self.scale = 1.0
0a45669 by Walter Bender at 2013-05-06 208
            self.entry_scale = 1.0
a64f47c by Walter Bender at 2010-11-20 209
            self.color_mode = '888'  # TODO: Read visual mode from gtk image
0a45669 by Walter Bender at 2013-05-06 210
        self._set_screen_dpi()
48ca444 by Walter Bender at 2010-08-22 211
3e898b8 by Walter Bender at 2011-03-07 212
        self.block_scale = BLOCK_SCALE[3]
c2937d9 by Walter Bender at 2010-08-12 213
        self.trash_scale = 0.5
8657fd5 by Walter Bender at 2010-11-16 214
        self.myblock = {}
215
        self.python_code = None
c2937d9 by Walter Bender at 2010-08-12 216
        self.nop = 'nop'
217
        self.loaded = 0
218
        self.step_time = 0
aca7f3c by Marion at 2013-07-03 219
        # show/ hide palettes depending on whether we're running in TA or not
220
        self.hide = not self.running_turtleart
221
        self.palette = self.running_turtleart
c2937d9 by Walter Bender at 2010-08-12 222
        self.coord_scale = 1
223
        self.buddies = []
e8f85f0 by Walter Bender at 2012-10-24 224
        self._saved_string = ''
52b0e32 by Walter Bender at 2012-06-16 225
        self._saved_action_name = ''
226
        self._saved_box_name = ''
c2937d9 by Walter Bender at 2010-08-12 227
        self.dx = 0
228
        self.dy = 0
229
        self.media_shapes = {}
230
        self.cartesian = False
231
        self.polar = False
3015923 by Walter Bender at 2011-06-09 232
        self.metric = False
c2937d9 by Walter Bender at 2010-08-12 233
        self.overlay_shapes = {}
234
        self.toolbar_shapes = {}
235
        self.toolbar_offset = 0
236
        self.status_spr = None
237
        self.status_shapes = {}
238
        self.toolbar_spr = None
239
        self.palette_sprs = []
240
        self.palettes = []
241
        self.palette_button = []
242
        self.trash_stack = []
243
        self.selected_palette = None
244
        self.previous_palette = None
245
        self.selectors = []
246
        self.selected_selector = None
247
        self.previous_selector = None
248
        self.selector_shapes = []
249
        self.selected_blk = None
250
        self.selected_spr = None
c244f86 by Walter Bender at 2011-11-04 251
        self.selected_turtle = None
c2937d9 by Walter Bender at 2010-08-12 252
        self.drag_group = None
253
        self.drag_turtle = 'move', 0, 0
254
        self.drag_pos = 0, 0
60d0d9c by Walter Bender at 2012-04-10 255
        self.dragging_canvas = [False, 0, 0]
5ddf280 by Walter Bender at 2011-10-06 256
        self.turtle_movement_to_share = None
c244f86 by Walter Bender at 2011-11-04 257
        self.paste_offset = 20  # Don't paste on top of where you copied.
48ca444 by Walter Bender at 2010-08-22 258
aca7f3c by Marion at 2013-07-03 259
        # common properties of all blocks (font size, decimal point, ...)
5acdeb5 by Walter Bender at 2010-09-28 260
        self.block_list = Blocks(font_scale_factor=self.scale,
261
                                 decimal_point=self.decimal_point)
c2937d9 by Walter Bender at 2010-08-12 262
        if self.interactive_mode:
ef080ed by Walter Bender at 2011-10-30 263
            self.sprite_list = Sprites(self.window)
c2937d9 by Walter Bender at 2010-08-12 264
        else:
2c58151 by Walter Bender at 2010-08-22 265
            self.sprite_list = None
48ca444 by Walter Bender at 2010-08-22 266
aca7f3c by Marion at 2013-07-03 267
        # canvas object that supports the basic drawing functionality
c244f86 by Walter Bender at 2011-11-04 268
        self.canvas = TurtleGraphics(self, self.width, self.height)
256d247 by Walter Bender at 2012-01-05 269
        if self.hw == XO175 and self.canvas.width == 1024:
7eb786c by Walter Bender at 2012-12-23 270
            self.hw = XO30
09812f9 by Walter Bender at 2011-11-05 271
        if self.interactive_mode:
272
            self.sprite_list.set_cairo_context(self.canvas.canvas)
c244f86 by Walter Bender at 2011-11-04 273
0dda146 by Walter Bender at 2013-06-25 274
        self.turtles = Turtles(self)
275
        if self.nick is not None:
276
            self.turtles.set_default_turtle_name(self.nick)
2c58151 by Walter Bender at 2010-08-22 277
        if mycolors is None:
0dda146 by Walter Bender at 2013-06-25 278
            Turtle(self.turtles, self.turtles.get_default_turtle_name())
2c58151 by Walter Bender at 2010-08-22 279
        else:
0dda146 by Walter Bender at 2013-06-25 280
            Turtle(self.turtles, self.turtles.get_default_turtle_name(),
281
                   mycolors.split(','))
2aa89e8 by Walter Bender at 2013-06-26 282
        self.turtles.set_active_turtle(
283
            self.turtles.get_turtle(self.turtles.get_default_turtle_name()))
0dda146 by Walter Bender at 2013-06-25 284
        self.turtles.get_active_turtle().show()
48ca444 by Walter Bender at 2010-08-22 285
c244f86 by Walter Bender at 2011-11-04 286
        self.canvas.clearscreen(False)
48ca444 by Walter Bender at 2010-08-22 287
0d5407f by Walter Bender at 2013-02-22 288
        self._configure_cb(None)
48ca444 by Walter Bender at 2010-08-22 289
c3f0e8e by Walter Bender at 2011-04-07 290
        self._icon_paths = [os.path.join(self.path, 'icons')]
b9f147f by Walter Bender at 2010-12-29 291
292
        self.lc = LogoCode(self)
ea3a04b by Walter Bender at 2011-03-01 293
224c411 by Walter Bender at 2013-05-29 294
        self.turtleart_plugins = []
295
        self.saved_pictures = []
296
        self.block_operation = ''
297
aca7f3c by Marion at 2013-07-03 298
        # only in TA: setup basic palettes
299
        if self.running_turtleart:
300
            from tabasics import Palettes
301
            self._basic_palettes = Palettes(self)
b9f147f by Walter Bender at 2010-12-29 302
4ea385a by Walter Bender at 2011-02-27 303
        if self.interactive_mode:
224c411 by Walter Bender at 2013-05-29 304
            gobject.idle_add(self._lazy_init)
305
        else:
306
            self._init_plugins()
307
            self._setup_plugins()
308
aca7f3c by Marion at 2013-07-03 309
    def _lazy_init(self):
224c411 by Walter Bender at 2013-05-29 310
        self._init_plugins()
311
        self._setup_plugins()
aca7f3c by Marion at 2013-07-03 312
        self._setup_misc()
6f7d44e by Walter Bender at 2013-06-21 313
aca7f3c by Marion at 2013-07-03 314
        if self.running_turtleart:
6f7d44e by Walter Bender at 2013-06-21 315
            self._basic_palettes.make_trash_palette()
7794bee by Marion at 2013-06-20 316
            for name in palette_init_on_start:
317
                debug_output('initing palette %s' % (name), self.running_sugar)
318
                self.show_toolbar_palette(palette_names.index(name),
6f7d44e by Walter Bender at 2013-06-21 319
                                          init_only=False,
320
                                          regenerate=True,
7794bee by Marion at 2013-06-20 321
                                          show=False)
6f7d44e by Walter Bender at 2013-06-21 322
323
            self.show_toolbar_palette(0,
324
                                      init_only=False,
325
                                      regenerate=True,
7794bee by Marion at 2013-06-20 326
                                      show=True)
98ed32f by Walter Bender at 2013-06-03 327
224c411 by Walter Bender at 2013-05-29 328
        if self.running_sugar:
329
            self.activity.check_buttons_for_fit()
9b9061f by Walter Bender at 2010-12-24 330
2ef9a33 by Walter Bender at 2012-10-26 331
    def _set_screen_dpi(self):
332
        dpi = get_screen_dpi()
7eb786c by Walter Bender at 2012-12-23 333
        if self.hw in (XO1, XO15, XO175, XO4):
54f85f2 by Walter Bender at 2012-10-30 334
            dpi = 133  # Tweek because of XO display peculiarities
2ef9a33 by Walter Bender at 2012-10-26 335
        font_map_default = pangocairo.cairo_font_map_get_default()
336
        font_map_default.set_resolution(dpi)
337
e8f85f0 by Walter Bender at 2012-10-24 338
    def _tablet_mode(self):
339
        return False  # Sugar will autoscroll the window for me
340
0373970 by Walter Bender at 2011-02-18 341
    def _get_plugin_home(self):
2fee6e6 by Walter Bender at 2012-06-23 342
        ''' Look in the execution directory '''
11333ce by Walter Bender at 2013-05-22 343
        path = os.path.join(self.path, _PLUGIN_SUBPATH)
0373970 by Walter Bender at 2011-02-18 344
        if os.path.exists(path):
345
            return path
8bb0d55 by Walter Bender at 2011-02-23 346
        else:
347
            return None
0373970 by Walter Bender at 2011-02-18 348
c3f0e8e by Walter Bender at 2011-04-07 349
    def _get_plugins_from_plugins_dir(self, path):
2fee6e6 by Walter Bender at 2012-06-23 350
        ''' Look for plugin files in plugin dir. '''
8a742df by Walter Bender at 2011-04-04 351
        plugin_files = []
352
        if path is not None:
353
            candidates = os.listdir(path)
22b9bdf by Walter Bender at 2012-12-28 354
            candidates.sort()
8a742df by Walter Bender at 2011-04-04 355
            for dirname in candidates:
4fff361 by Walter Bender at 2013-05-22 356
                pname = os.path.join(path, dirname, dirname + '.py')
357
                if os.path.exists(pname):
8a742df by Walter Bender at 2011-04-04 358
                    plugin_files.append(dirname)
42db693 by Marion at 2013-06-21 359
        return plugin_files
8a742df by Walter Bender at 2011-04-04 360
0373970 by Walter Bender at 2011-02-18 361
    def _init_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 362
        ''' Try importing plugin files from the plugin dir. '''
4fff361 by Walter Bender at 2013-05-22 363
        plist = self._get_plugins_from_plugins_dir(self._get_plugin_home())
364
        for plugin_dir in plist:
0e8cd72 by Walter Bender at 2012-03-26 365
            self.init_plugin(plugin_dir)
366
367
    def init_plugin(self, plugin_dir):
2fee6e6 by Walter Bender at 2012-06-23 368
        ''' Initialize plugin in plugin_dir '''
0e8cd72 by Walter Bender at 2012-03-26 369
        plugin_class = plugin_dir.capitalize()
0ee623d by Walter Bender at 2013-07-23 370
        f = 'def f(self): from plugins.%s.%s import %s; return %s(self)' \
0e8cd72 by Walter Bender at 2012-03-26 371
            % (plugin_dir, plugin_dir, plugin_class, plugin_class)
372
        plugins = {}
d26a9f0 by Walter Bender at 2012-10-19 373
        # NOTE: When debugging plugins, it may be useful to not trap errors
0e8cd72 by Walter Bender at 2012-03-26 374
        try:
77b71c1 by Walter Bender at 2011-08-20 375
            exec f in globals(), plugins
b5b3754 by Walter Bender at 2012-11-08 376
            self.turtleart_plugins.append(plugins.values()[0](self))
4cb54af by Walter Bender at 2012-03-27 377
            debug_output('Successfully importing %s' % (plugin_class),
0e8cd72 by Walter Bender at 2012-03-26 378
                         self.running_sugar)
379
            # Add the icon dir to the icon_theme search path
c3f0e8e by Walter Bender at 2011-04-07 380
            self._add_plugin_icon_dir(os.path.join(self._get_plugin_home(),
381
                                                   plugin_dir))
edf6d46 by Walter Bender at 2013-03-21 382
        except Exception as e:
383
            debug_output('Failed to load %s: %s' % (plugin_class, str(e)),
10c8131 by Walter Bender at 2012-09-02 384
                         self.running_sugar)
c3f0e8e by Walter Bender at 2011-04-07 385
386
    def _add_plugin_icon_dir(self, dirname):
387
        ''' If there is an icon subdir, add it to the search path. '''
388
        icon_theme = gtk.icon_theme_get_default()
389
        icon_path = os.path.join(dirname, 'icons')
390
        if os.path.exists(icon_path):
391
            icon_theme.append_search_path(icon_path)
392
            self._icon_paths.append(icon_path)
0373970 by Walter Bender at 2011-02-18 393
e4fb242 by Walter Bender at 2012-02-08 394
    def _get_plugin_instance(self, plugin_name):
2fee6e6 by Walter Bender at 2012-06-23 395
        ''' Returns the plugin 'plugin_name' instance '''
e4fb242 by Walter Bender at 2012-02-08 396
        list_plugins = self._get_plugins_from_plugins_dir(
397
            self._get_plugin_home())
398
        if plugin_name in list_plugins:
399
            number_plugin = list_plugins.index(plugin_name)
b5b3754 by Walter Bender at 2012-11-08 400
            return self.turtleart_plugins[number_plugin]
e4fb242 by Walter Bender at 2012-02-08 401
        else:
402
            return None
403
05437dd by Walter Bender at 2011-02-19 404
    def _setup_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 405
        ''' Initial setup -- called just once. '''
b5b3754 by Walter Bender at 2012-11-08 406
        for plugin in self.turtleart_plugins:
b96178d by Walter Bender at 2011-02-19 407
            plugin.setup()
0373970 by Walter Bender at 2011-02-18 408
05437dd by Walter Bender at 2011-02-19 409
    def _start_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 410
        ''' Start is called everytime we execute blocks. '''
b5b3754 by Walter Bender at 2012-11-08 411
        for plugin in self.turtleart_plugins:
b96178d by Walter Bender at 2011-02-19 412
            plugin.start()
05437dd by Walter Bender at 2011-02-19 413
9472d89 by Walter Bender at 2012-11-08 414
    def stop_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 415
        ''' Stop is called whenever we stop execution. '''
b5b3754 by Walter Bender at 2012-11-08 416
        for plugin in self.turtleart_plugins:
b96178d by Walter Bender at 2011-02-19 417
            plugin.stop()
05437dd by Walter Bender at 2011-02-19 418
260a1fe by Walter Bender at 2011-11-14 419
    def clear_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 420
        ''' Clear is called from the clean block and erase button. '''
b5b3754 by Walter Bender at 2012-11-08 421
        for plugin in self.turtleart_plugins:
260a1fe by Walter Bender at 2011-11-14 422
            if hasattr(plugin, 'clear'):
423
                plugin.clear()
424
c4f1fee by Walter Bender at 2011-02-19 425
    def background_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 426
        ''' Background is called when we are pushed to the background. '''
b5b3754 by Walter Bender at 2012-11-08 427
        for plugin in self.turtleart_plugins:
c4f1fee by Walter Bender at 2011-02-19 428
            plugin.goto_background()
429
430
    def foreground_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 431
        ''' Foreground is called when we are return from the background. '''
b5b3754 by Walter Bender at 2012-11-08 432
        for plugin in self.turtleart_plugins:
c4f1fee by Walter Bender at 2011-02-19 433
            plugin.return_to_foreground()
434
79c6a7d by Walter Bender at 2012-02-04 435
    def quit_plugins(self):
2fee6e6 by Walter Bender at 2012-06-23 436
        ''' Quit is called upon program exit. '''
b5b3754 by Walter Bender at 2012-11-08 437
        for plugin in self.turtleart_plugins:
b96178d by Walter Bender at 2011-02-19 438
            plugin.quit()
c2937d9 by Walter Bender at 2010-08-12 439
440
    def _setup_events(self):
2fee6e6 by Walter Bender at 2012-06-23 441
        ''' Register the events we listen to. '''
c2937d9 by Walter Bender at 2010-08-12 442
        self.window.add_events(gtk.gdk.BUTTON_PRESS_MASK)
443
        self.window.add_events(gtk.gdk.BUTTON_RELEASE_MASK)
444
        self.window.add_events(gtk.gdk.POINTER_MOTION_MASK)
445
        self.window.add_events(gtk.gdk.KEY_PRESS_MASK)
0ee623d by Walter Bender at 2013-07-23 446
        self.window.connect('expose-event', self._expose_cb)
447
        self.window.connect('button-press-event', self._buttonpress_cb)
448
        self.window.connect('button-release-event', self._buttonrelease_cb)
449
        self.window.connect('motion-notify-event', self._move_cb)
450
        self.window.connect('key-press-event', self._keypress_cb)
4fff361 by Walter Bender at 2013-05-22 451
        gtk.gdk.screen_get_default().connect('size-changed',
452
                                             self._configure_cb)
c2937d9 by Walter Bender at 2010-08-12 453
0ee623d by Walter Bender at 2013-07-23 454
        target = [('text/plain', 0, 0)]
b99d698 by Walter Bender at 2012-07-12 455
        self.window.drag_dest_set(gtk.DEST_DEFAULT_ALL, target,
4fff361 by Walter Bender at 2013-05-22 456
                                  gtk.gdk.ACTION_COPY | gtk.gdk.ACTION_MOVE)
b99d698 by Walter Bender at 2012-07-12 457
        self.window.connect('drag_data_received', self._drag_data_received)
458
112a8d7 by Walter Bender at 2013-05-01 459
    def _show_unfullscreen_button(self):
4fff361 by Walter Bender at 2013-05-22 460
        if self.activity._is_fullscreen and \
112a8d7 by Walter Bender at 2013-05-01 461
                self.activity.props.enable_fullscreen_mode:
462
            if not self.activity._unfullscreen_button.props.visible:
463
                self.activity._unfullscreen_button.show()
464
        # Reset the timer
465
        if self.activity._unfullscreen_button_timeout_id is not None:
4fff361 by Walter Bender at 2013-05-22 466
            gobject.source_remove(
467
                self.activity._unfullscreen_button_timeout_id)
112a8d7 by Walter Bender at 2013-05-01 468
            self.activity._unfullscreen_button_timeout_id = None
4fff361 by Walter Bender at 2013-05-22 469
470
        self.activity._unfullscreen_button_timeout_id = \
471
            gobject.timeout_add_seconds(_UNFULLSCREEN_VISIBILITY_TIMEOUT,
472
                                        self.__unfullscreen_button_timeout_cb)
112a8d7 by Walter Bender at 2013-05-01 473
474
    def __unfullscreen_button_timeout_cb(self):
4fff361 by Walter Bender at 2013-05-22 475
        self.activity._unfullscreen_button.hide()
112a8d7 by Walter Bender at 2013-05-01 476
b99d698 by Walter Bender at 2012-07-12 477
    def _drag_data_received(self, w, context, x, y, data, info, time):
478
        ''' Handle dragging of block data from clipboard to canvas. '''
479
        debug_output(data.data, True)
480
        if data and data.format == 8 and data.data[0:2] == '[[':
481
            self.process_data(data_from_string(data.data),
482
                              self.paste_offset)
483
            self.paste_offset += 20
484
            context.finish(True, False, time)
485
        elif data and data.format == 8 and \
4fff361 by Walter Bender at 2013-05-22 486
                self.selected_blk is not None and \
487
                self.selected_blk.name == 'string':
4273124 by Walter Bender at 2012-11-28 488
            bounds = self._text_buffer.get_bounds()
489
            self._text_buffer.set_text(
490
                self._text_buffer.get_text(bounds[0], bounds[1]) + data.data)
e8f85f0 by Walter Bender at 2012-10-24 491
            self.text_entry.set_buffer(self._text_buffer)
b99d698 by Walter Bender at 2012-07-12 492
            context.finish(True, False, time)
493
        else:
494
            context.finish(False, False, time)
495
609f182 by Walter Bender at 2012-03-26 496
    def load_media_shapes(self):
2fee6e6 by Walter Bender at 2012-06-23 497
        ''' Media shapes get positioned onto blocks '''
c3f0e8e by Walter Bender at 2011-04-07 498
        for name in MEDIA_SHAPES:
609f182 by Walter Bender at 2012-03-26 499
            if name in self.media_shapes:
500
                continue
c3f0e8e by Walter Bender at 2011-04-07 501
            if name[0:7] == 'journal' and not self.running_sugar:
502
                filename = 'file' + name[7:]
c2937d9 by Walter Bender at 2010-08-12 503
            else:
c3f0e8e by Walter Bender at 2011-04-07 504
                filename = name
ae91c9c by Walter Bender at 2011-07-26 505
            # Try both images/ and plugins/*/images/
506
            for path in SKIN_PATHS:
507
                if os.path.exists(os.path.join(self.path, path,
508
                                               filename + '.svg')):
4fff361 by Walter Bender at 2013-05-22 509
                    self.media_shapes[name] = svg_str_to_pixbuf(
510
                        svg_from_file(
ae91c9c by Walter Bender at 2011-07-26 511
                            os.path.join(self.path, path, filename + '.svg')))
512
                    break
c2937d9 by Walter Bender at 2010-08-12 513
aca7f3c by Marion at 2013-07-03 514
    def _setup_misc(self):
515
        ''' Misc. sprites for status, overlays, etc. '''
609f182 by Walter Bender at 2012-03-26 516
        self.load_media_shapes()
c3f0e8e by Walter Bender at 2011-04-07 517
        for i, name in enumerate(STATUS_SHAPES):
c328592 by Walter Bender at 2012-04-03 518
            # Temporary hack to use wider shapes
519
            if name in ['print', 'help', 'status'] and self.width > 1024:
4fff361 by Walter Bender at 2013-05-22 520
                self.status_shapes[name] = svg_str_to_pixbuf(
521
                    svg_from_file(
c328592 by Walter Bender at 2012-04-03 522
                        os.path.join(self.path, 'images', name + '1200.svg')))
523
            else:
4fff361 by Walter Bender at 2013-05-22 524
                self.status_shapes[name] = svg_str_to_pixbuf(
525
                    svg_from_file(
c328592 by Walter Bender at 2012-04-03 526
                        os.path.join(self.path, 'images', name + '.svg')))
dcd7408 by Walter Bender at 2010-10-10 527
        self.status_spr = Sprite(self.sprite_list, 0, self.height - 200,
48ca444 by Walter Bender at 2010-08-22 528
                                 self.status_shapes['status'])
c2937d9 by Walter Bender at 2010-08-12 529
        self.status_spr.hide()
530
        self.status_spr.type = 'status'
8d09405 by Walter Bender at 2012-10-19 531
        self._autohide_shape = True
c2937d9 by Walter Bender at 2010-08-12 532
c3f0e8e by Walter Bender at 2011-04-07 533
        for name in OVERLAY_SHAPES:
6da711c by Walter Bender at 2013-08-23 534
            if name == 'Cartesian':
535
                continue
4fff361 by Walter Bender at 2013-05-22 536
            self.overlay_shapes[name] = Sprite(
537
                self.sprite_list,
538
                int(self.width / 2 - 600),
539
                int(self.height / 2 - 450),
540
                svg_str_to_pixbuf(
0ee623d by Walter Bender at 2013-07-23 541
                    svg_from_file('%s/images/%s.svg' % (self.path, name))))
c3f0e8e by Walter Bender at 2011-04-07 542
            self.overlay_shapes[name].hide()
543
            self.overlay_shapes[name].type = 'overlay'
c2937d9 by Walter Bender at 2010-08-12 544
6da711c by Walter Bender at 2013-08-23 545
        self._create_scaled_cartesian_coordinates()
546
aca7f3c by Marion at 2013-07-03 547
        if self.running_turtleart and not self.running_sugar:
0c3b8bc by Walter Bender at 2012-05-03 548
            # offset = 2 * self.width - 55 * len(TOOLBAR_SHAPES)
63cc9bb by Walter Bender at 2013-03-13 549
            offset = 55 * (1 + len(palette_blocks))
c3f0e8e by Walter Bender at 2011-04-07 550
            for i, name in enumerate(TOOLBAR_SHAPES):
551
                self.toolbar_shapes[name] = Sprite(
552
                    self.sprite_list, i * 55 + offset, 0,
4fff361 by Walter Bender at 2013-05-22 553
                    svg_str_to_pixbuf(
554
                        svg_from_file(
555
                            os.path.join(
c3f0e8e by Walter Bender at 2011-04-07 556
                                self.path, 'icons', '%s.svg' % (name)))))
557
                self.toolbar_shapes[name].set_layer(TAB_LAYER)
558
                self.toolbar_shapes[name].name = name
559
                self.toolbar_shapes[name].type = 'toolbar'
c2937d9 by Walter Bender at 2010-08-12 560
            self.toolbar_shapes['stopiton'].hide()
561
6da711c by Walter Bender at 2013-08-23 562
    def _create_scaled_cartesian_coordinates(self):
563
        # Cartesian overlay has to be scaled to match the coordinate_scale
564
        # 200 pixels in the graphic == height / 4. (10 units)
565
        pixbuf = svg_str_to_pixbuf(
566
            svg_from_file('%s/images/%s.svg' % (self.path, 'Cartesian')))
567
        
568
        if self.running_sugar:
569
            scale = self.height / 800.
570
        else:
624c945 by Walter Bender at 2013-08-26 571
            scale = self.height / 800.
572
            # scale = (self.height + ICON_SIZE) / 800.
6da711c by Walter Bender at 2013-08-23 573
        self.overlay_shapes['Cartesian'] = Sprite(
574
            self.sprite_list,
575
            int(self.width / 2 - 600),
576
            int(self.height / 2 - 450),
577
            pixbuf.scale_simple(int(1200 * scale),
578
                                int(900 * scale),
579
                                gtk.gdk.INTERP_BILINEAR))
580
        self.overlay_shapes['Cartesian'].set_layer(TAB_LAYER)
581
        self.overlay_shapes['Cartesian'].hide()
582
725ac09 by Raul Gutierrez Segales at 2011-02-02 583
    def set_sharing(self, shared):
584
        self._sharing = shared
9905da9 by Raul Gutierrez Segales at 2011-01-25 585
725ac09 by Raul Gutierrez Segales at 2011-02-02 586
    def sharing(self):
587
        return self._sharing
c2937d9 by Walter Bender at 2010-08-12 588
589
    def is_project_empty(self):
2fee6e6 by Walter Bender at 2012-06-23 590
        ''' Check to see if project has any blocks in use '''
c2937d9 by Walter Bender at 2010-08-12 591
        return len(self.just_blocks()) == 1
592
0d5407f by Walter Bender at 2013-02-22 593
    def _configure_cb(self, event):
594
        ''' Screen size has changed '''
595
        self.width = gtk.gdk.screen_width()
596
        self.height = gtk.gdk.screen_height()
4fff361 by Walter Bender at 2013-05-22 597
        CONSTANTS['titlex'] = int(-(self.width * TITLEXY[0]) /
598
                                   (self.coord_scale * 2))
599
        CONSTANTS['leftx'] = int(-(self.width * TITLEXY[0]) /
600
                                  (self.coord_scale * 2))
0d5407f by Walter Bender at 2013-02-22 601
        CONSTANTS['rightx'] = 0
4fff361 by Walter Bender at 2013-05-22 602
        CONSTANTS['titley'] = int((self.height * TITLEXY[1]) /
603
                                  (self.coord_scale * 2))
604
        CONSTANTS['topy'] = int((self.height * (TITLEXY[1] - 0.125)) /
605
                                (self.coord_scale * 2))
0d5407f by Walter Bender at 2013-02-22 606
        CONSTANTS['bottomy'] = 0
607
        CONSTANTS['leftpos'] = int(-self.width / (self.coord_scale * 2))
608
        CONSTANTS['toppos'] = int(self.height / (self.coord_scale * 2))
609
        CONSTANTS['rightpos'] = int(self.width / (self.coord_scale * 2))
610
        CONSTANTS['bottompos'] = int(-self.height / (self.coord_scale * 2))
611
        CONSTANTS['width'] = int(self.width / self.coord_scale)
612
        CONSTANTS['height'] = int(self.height / self.coord_scale)
613
614
        if event is None:
615
            return
616
53050dc by Walter Bender at 2013-02-23 617
        self.activity.check_buttons_for_fit()
618
0d5407f by Walter Bender at 2013-02-22 619
        # If there are any constant blocks on the canvas, relabel them
620
        for blk in self.just_blocks():
621
            if blk.name in ['leftpos', 'toppos', 'rightpos', 'bottompos',
622
                            'width', 'height']:
623
                blk.spr.set_label('%s = %d' % (block_names[blk.name][0],
624
                                               CONSTANTS[blk.name]))
625
                blk.resize()
626
ef080ed by Walter Bender at 2011-10-30 627
    def _expose_cb(self, win=None, event=None):
2fee6e6 by Walter Bender at 2012-06-23 628
        ''' Repaint '''
ef080ed by Walter Bender at 2011-10-30 629
        self.do_expose_event(event)
c2937d9 by Walter Bender at 2010-08-12 630
        return True
631
ef080ed by Walter Bender at 2011-10-30 632
    def do_expose_event(self, event=None):
144d719 by Walter Bender at 2012-06-23 633
        ''' Handle the expose-event by drawing '''
ef080ed by Walter Bender at 2011-10-30 634
635
        # Create the cairo context
636
        cr = self.window.window.cairo_create()
7eb786c by Walter Bender at 2012-12-23 637
4dfcb24 by Walter Bender at 2012-04-18 638
        # TODO: set global scale
639
        # find_sprite needs rescaled coordinates
640
        # sw needs new bounds set
641
        # cr.scale(self.activity.global_x_scale, self.activity.global_y_scale)
ef080ed by Walter Bender at 2011-10-30 642
643
        if event is None:
644
            cr.rectangle(self.rect.x, self.rect.y,
645
                         self.rect.width, self.rect.height)
646
        else:
647
        # Restrict Cairo to the exposed area; avoid extra work
648
            cr.rectangle(event.area.x, event.area.y,
649
                         event.area.width, event.area.height)
650
        cr.clip()
651
652
        if self.turtle_canvas is not None:
653
            cr.set_source_surface(self.turtle_canvas)
654
            cr.paint()
655
656
        # Refresh sprite list
657
        self.sprite_list.redraw_sprites(cr=cr)
658
c2937d9 by Walter Bender at 2010-08-12 659
    def eraser_button(self):
2fee6e6 by Walter Bender at 2012-06-23 660
        ''' Eraser_button (hide status block when clearing the screen.) '''
c2937d9 by Walter Bender at 2010-08-12 661
        if self.status_spr is not None:
662
            self.status_spr.hide()
8d09405 by Walter Bender at 2012-10-19 663
        self._autohide_shape = True
30028d7 by Walter Bender at 2011-11-12 664
        self.lc.find_value_blocks()  # Are there blocks to update?
c2937d9 by Walter Bender at 2010-08-12 665
        self.lc.prim_clear()
666
        self.display_coordinates()
667
29cd6b6 by Walter Bender at 2012-05-01 668
    def run_button(self, time, running_from_button_push=False):
2fee6e6 by Walter Bender at 2012-06-23 669
        ''' Run turtle! '''
c2937d9 by Walter Bender at 2010-08-12 670
        if self.running_sugar:
671
            self.activity.recenter()
7eb786c by Walter Bender at 2012-12-23 672
c2937d9 by Walter Bender at 2010-08-12 673
        # Look for a 'start' block
674
        for blk in self.just_blocks():
675
            if find_start_stack(blk):
676
                self.step_time = time
f038f28 by Walter Bender at 2012-12-24 677
                if self.running_sugar:
0ee623d by Walter Bender at 2013-07-23 678
                    debug_output('running stack starting from %s' % (blk.name),
f038f28 by Walter Bender at 2012-12-24 679
                                 self.running_sugar)
29cd6b6 by Walter Bender at 2012-05-01 680
                if running_from_button_push:
681
                    self.selected_blk = None
682
                else:
683
                    self.selected_blk = blk
c2937d9 by Walter Bender at 2010-08-12 684
                self._run_stack(blk)
685
                return
48ca444 by Walter Bender at 2010-08-22 686
c2937d9 by Walter Bender at 2010-08-12 687
        # If there is no 'start' block, run stacks that aren't 'def action'
688
        for blk in self.just_blocks():
689
            if find_block_to_run(blk):
690
                self.step_time = time
48a193b by Walter Bender at 2012-07-11 691
                if self.running_sugar:
0ee623d by Walter Bender at 2013-07-23 692
                    debug_output('running stack starting from %s' % (blk.name),
48a193b by Walter Bender at 2012-07-11 693
                                 self.running_sugar)
29cd6b6 by Walter Bender at 2012-05-01 694
                if running_from_button_push:
695
                    self.selected_blk = None
696
                else:
697
                    self.selected_blk = blk
c2937d9 by Walter Bender at 2010-08-12 698
                self._run_stack(blk)
699
        return
700
701
    def stop_button(self):
2fee6e6 by Walter Bender at 2012-06-23 702
        ''' Stop button '''
29abcea by Walter Bender at 2011-02-15 703
        self.lc.stop_logo()
c2937d9 by Walter Bender at 2010-08-12 704
8657fd5 by Walter Bender at 2010-11-16 705
    def set_userdefined(self, blk=None):
2fee6e6 by Walter Bender at 2012-06-23 706
        ''' Change icon for user-defined blocks after loading Python code. '''
8657fd5 by Walter Bender at 2010-11-16 707
        if blk is not None:
c2937d9 by Walter Bender at 2010-08-12 708
            if blk.name in PYTHON_SKIN:
709
                x, y = self._calc_image_offset('pythonon', blk.spr)
710
                blk.set_image(self.media_shapes['pythonon'], x, y)
711
                self._resize_skin(blk)
712
713
    def set_fullscreen(self):
2fee6e6 by Walter Bender at 2012-06-23 714
        ''' Enter fullscreen mode '''
c2937d9 by Walter Bender at 2010-08-12 715
        if self.running_sugar:
716
            self.activity.fullscreen()
717
            self.activity.recenter()
718
719
    def set_cartesian(self, flag):
2fee6e6 by Walter Bender at 2012-06-23 720
        ''' Turn on/off Cartesian coordinates '''
a7a87c7 by Walter Bender at 2011-11-07 721
        if self.coord_scale == 1:
722
            self.draw_overlay('Cartesian_labeled')
723
        else:
724
            self.draw_overlay('Cartesian')
725
        return
c2937d9 by Walter Bender at 2010-08-12 726
727
    def set_polar(self, flag):
2fee6e6 by Walter Bender at 2012-06-23 728
        ''' Turn on/off polar coordinates '''
a7a87c7 by Walter Bender at 2011-11-07 729
        self.draw_overlay('polar')
730
        return
c2937d9 by Walter Bender at 2010-08-12 731
3015923 by Walter Bender at 2011-06-09 732
    def set_metric(self, flag):
2fee6e6 by Walter Bender at 2012-06-23 733
        ''' Turn on/off metric coordinates '''
a7a87c7 by Walter Bender at 2011-11-07 734
        self.draw_overlay('metric')
735
        return
736
737
    def draw_overlay(self, overlay):
738
        ''' Draw a coordinate grid onto the canvas. '''
0dda146 by Walter Bender at 2013-06-25 739
        width = self.overlay_shapes[overlay].rect[2]
740
        height = self.overlay_shapes[overlay].rect[3]
741
        if self.running_sugar:
742
            y_offset = 0
743
        else:
624c945 by Walter Bender at 2013-08-26 744
            y_offset = 0
745
            # y_offset = ICON_SIZE
21a529e by Walter Bender at 2011-11-11 746
        self.canvas.draw_surface(
747
            self.overlay_shapes[overlay].cached_surfaces[0],
0dda146 by Walter Bender at 2013-06-25 748
            (self.canvas.width - width) / 2.0,
749
            (self.canvas.height - height + y_offset) / 2.0,
750
            width,
751
            height)
3015923 by Walter Bender at 2011-06-09 752
624c945 by Walter Bender at 2013-08-26 753
    def update_overlay_position(self, widget=None, event=None):
2fee6e6 by Walter Bender at 2012-06-23 754
        ''' Reposition the overlays when window size changes '''
624c945 by Walter Bender at 2013-08-26 755
        # self.width = event.width
756
        # self.height = event.height
757
        self.width = gtk.gdk.screen_width()
758
        self.height = gtk.gdk.screen_height()
759
c3f0e8e by Walter Bender at 2011-04-07 760
        for name in OVERLAY_SHAPES:
224c411 by Walter Bender at 2013-05-29 761
            if not name in self.overlay_shapes:
762
                continue
c3f0e8e by Walter Bender at 2011-04-07 763
            shape = self.overlay_shapes[name]
c2937d9 by Walter Bender at 2010-08-12 764
            showing = False
765
            if shape in shape._sprites.list:
766
                shape.hide()
767
                showing = True
624c945 by Walter Bender at 2013-08-26 768
            self.overlay_shapes[name].move((int(self.width / 2 - 600),
769
                                            int(self.height / 2 - 450)))
770
            '''
4fff361 by Walter Bender at 2013-05-22 771
            self.overlay_shapes[name] = Sprite(
772
                self.sprite_list,
773
                int(self.width / 2 - 600),
774
                int(self.height / 2 - 450),
775
                svg_str_to_pixbuf(
0ee623d by Walter Bender at 2013-07-23 776
                    svg_from_file('%s/images/%s.svg' % (self.path, name))))
624c945 by Walter Bender at 2013-08-26 777
            '''
c2937d9 by Walter Bender at 2010-08-12 778
            if showing:
c3f0e8e by Walter Bender at 2011-04-07 779
                self.overlay_shapes[name].set_layer(OVERLAY_LAYER)
c2937d9 by Walter Bender at 2010-08-12 780
            else:
c3f0e8e by Walter Bender at 2011-04-07 781
                self.overlay_shapes[name].hide()
624c945 by Walter Bender at 2013-08-26 782
            '''
c3f0e8e by Walter Bender at 2011-04-07 783
            self.overlay_shapes[name].type = 'overlay'
624c945 by Walter Bender at 2013-08-26 784
            '''
785
c2937d9 by Walter Bender at 2010-08-12 786
        self.cartesian = False
787
        self.polar = False
3015923 by Walter Bender at 2011-06-09 788
        self.metric = False
c2937d9 by Walter Bender at 2010-08-12 789
        self.canvas.width = self.width
790
        self.canvas.height = self.height
0dda146 by Walter Bender at 2013-06-25 791
        self.turtles.get_active_turtle().move_turtle()
c2937d9 by Walter Bender at 2010-08-12 792
793
    def hideshow_button(self):
2fee6e6 by Walter Bender at 2012-06-23 794
        ''' Hide/show button '''
dcd7408 by Walter Bender at 2010-10-10 795
        if not self.hide:
c2937d9 by Walter Bender at 2010-08-12 796
            for blk in self.just_blocks():
797
                blk.spr.hide()
dcd7408 by Walter Bender at 2010-10-10 798
            self.hide_palette()
c2937d9 by Walter Bender at 2010-08-12 799
            self.hide = True
800
        else:
801
            for blk in self.just_blocks():
802
                if blk.status != 'collapsed':
803
                    blk.spr.set_layer(BLOCK_LAYER)
804
            self.show_palette()
805
            self.hide = False
f1d00e0 by Walter Bender at 2010-09-25 806
            if self.running_sugar:
807
                self.activity.recenter()
0150810 by Walter Bender at 2011-11-03 808
        self.inval_all()
f1d00e0 by Walter Bender at 2010-09-25 809
0150810 by Walter Bender at 2011-11-03 810
    def inval_all(self):
2fee6e6 by Walter Bender at 2012-06-23 811
        ''' Force a refresh '''
09812f9 by Walter Bender at 2011-11-05 812
        if self.interactive_mode:
813
            self.window.queue_draw_area(0, 0, self.width, self.height)
c2937d9 by Walter Bender at 2010-08-12 814
815
    def hideshow_palette(self, state):
2fee6e6 by Walter Bender at 2012-06-23 816
        ''' Hide or show palette  '''
c2937d9 by Walter Bender at 2010-08-12 817
        if not state:
818
            self.palette = False
819
            if self.running_sugar:
820
                self.activity.do_hidepalette()
821
            self.hide_palette()
822
        else:
823
            self.palette = True
824
            if self.running_sugar:
825
                self.activity.do_showpalette()
f1d00e0 by Walter Bender at 2010-09-25 826
                self.activity.recenter()
c2937d9 by Walter Bender at 2010-08-12 827
            self.show_palette()
828
0d23632 by Walter Bender at 2012-02-04 829
    def show_palette(self, n=None):
2fee6e6 by Walter Bender at 2012-06-23 830
        ''' Show palette. '''
0d23632 by Walter Bender at 2012-02-04 831
        if n is None:
832
            if self.selected_palette is None:
833
                n = 0
834
            else:
835
                n = self.selected_palette
89e9f18 by Walter Bender at 2011-03-19 836
        self.show_toolbar_palette(n)
c2937d9 by Walter Bender at 2010-08-12 837
        self.palette_button[self.orientation].set_layer(TAB_LAYER)
838
        self.palette_button[2].set_layer(TAB_LAYER)
89cb13a by Walter Bender at 2012-03-28 839
        self._display_palette_shift_button(n)
d83cb4e by Walter Bender at 2012-10-19 840
        if not self.running_sugar or not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 841
            self.toolbar_spr.set_layer(CATEGORY_LAYER)
842
        self.palette = True
6b2f360 by Walter Bender at 2013-08-21 843
        self._set_coordinates_label(palette_names[n])
c2937d9 by Walter Bender at 2010-08-12 844
845
    def hide_palette(self):
2fee6e6 by Walter Bender at 2012-06-23 846
        ''' Hide the palette. '''
c2937d9 by Walter Bender at 2010-08-12 847
        self._hide_toolbar_palette()
bc0ba2c by Walter Bender at 2013-03-08 848
        for button in self.palette_button:
849
            button.hide()
6f0642b by Walter Bender at 2012-10-20 850
        if not self.running_sugar or not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 851
            self.toolbar_spr.hide()
852
        self.palette = False
853
cfe8338 by Walter Bender at 2011-10-03 854
    def move_palettes(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 855
        ''' Move the palettes. '''
cfe8338 by Walter Bender at 2011-10-03 856
        for p in self.palettes:
857
            for blk in p:
858
                blk.spr.move((x + blk.spr.save_xy[0], y + blk.spr.save_xy[1]))
859
        for spr in self.palette_button:
860
            spr.move((x + spr.save_xy[0], y + spr.save_xy[1]))
861
        for p in self.palette_sprs:
862
            if p[0] is not None:
863
                p[0].move((x + p[0].save_xy[0], y + p[0].save_xy[1]))
864
            if p[1] is not None:
865
                p[1].move((x + p[1].save_xy[0], y + p[1].save_xy[1]))
155970b by Walter Bender at 2012-03-23 866
867
        self.status_spr.move((x + self.status_spr.save_xy[0],
868
                              y + self.status_spr.save_xy[1]))
869
744b9c1 by Walter Bender at 2011-10-03 870
        # To do: set save_xy for blocks in Trash
871
        for blk in self.trash_stack:
872
            for gblk in find_group(blk):
873
                gblk.spr.move((x + gblk.spr.save_xy[0],
874
                               y + gblk.spr.save_xy[1]))
cfe8338 by Walter Bender at 2011-10-03 875
c2937d9 by Walter Bender at 2010-08-12 876
    def hideblocks(self):
2fee6e6 by Walter Bender at 2012-06-23 877
        ''' Callback from 'hide blocks' block '''
c2937d9 by Walter Bender at 2010-08-12 878
        if not self.interactive_mode:
879
            return
880
        self.hide = False
881
        self.hideshow_button()
882
        if self.running_sugar:
b6eca78 by Walter Bender at 2011-04-14 883
            self.activity.do_hide_blocks()
c2937d9 by Walter Bender at 2010-08-12 884
885
    def showblocks(self):
2fee6e6 by Walter Bender at 2012-06-23 886
        ''' Callback from 'show blocks' block '''
c2937d9 by Walter Bender at 2010-08-12 887
        if not self.interactive_mode:
888
            return
889
        self.hide = True
890
        self.hideshow_button()
891
        if self.running_sugar:
b6eca78 by Walter Bender at 2011-04-14 892
            self.activity.do_show_blocks()
c2937d9 by Walter Bender at 2010-08-12 893
894
    def resize_blocks(self, blocks=None):
2fee6e6 by Walter Bender at 2012-06-23 895
        ''' Resize blocks or if blocks is None, all of the blocks '''
c2937d9 by Walter Bender at 2010-08-12 896
        if blocks is None:
897
            blocks = self.just_blocks()
898
899
        # Do the resizing.
900
        for blk in blocks:
901
            blk.rescale(self.block_scale)
902
        for blk in blocks:
903
            self._adjust_dock_positions(blk)
904
905
        # Resize the skins on some blocks: media content and Python
906
        for blk in blocks:
907
            if blk.name in BLOCKS_WITH_SKIN:
908
                self._resize_skin(blk)
909
c83fa3c by Walter Bender at 2012-10-25 910
        # Resize text_entry widget
911
        if hasattr(self, '_text_entry') and len(blocks) > 0:
912
            font_desc = pango.FontDescription('Sans')
54f85f2 by Walter Bender at 2012-10-30 913
            font_desc.set_size(
914
                int(blocks[0].font_size[0] * pango.SCALE * self.entry_scale))
c83fa3c by Walter Bender at 2012-10-25 915
            self._text_entry.modify_font(font_desc)
916
89cb13a by Walter Bender at 2012-03-28 917
    def _shift_toolbar_palette(self, n):
918
        ''' Shift blocks on specified palette '''
919
        x, y = self.palette_sprs[n][self.orientation].get_xy()
920
        w, h = self.palette_sprs[n][self.orientation].get_dimensions()
921
        bx, by = self.palettes[n][0].spr.get_xy()
922
        if self.orientation == 0:
11333ce by Walter Bender at 2013-05-22 923
            if bx != _BUTTON_SIZE:
bc0ba2c by Walter Bender at 2013-03-08 924
                dx = w - self.width
925
            else:
926
                dx = self.width - w
89cb13a by Walter Bender at 2012-03-28 927
            dy = 0
928
        else:
929
            dx = 0
11333ce by Walter Bender at 2013-05-22 930
            if by != self.toolbar_offset + _BUTTON_SIZE + _MARGIN:
bc0ba2c by Walter Bender at 2013-03-08 931
                dy = h - self.height + ICON_SIZE
932
            else:
933
                dy = self.height - h - ICON_SIZE
89cb13a by Walter Bender at 2012-03-28 934
        for blk in self.palettes[n]:
935
            if blk.get_visibility():
936
                blk.spr.move_relative((dx, dy))
c855d75 by Walter Bender at 2013-03-01 937
        self.palette_button[self.orientation].set_layer(TOP_LAYER)
bc0ba2c by Walter Bender at 2013-03-08 938
        if dx < 0 or dy < 0:
939
            self.palette_button[self.orientation + 5].set_layer(TOP_LAYER)
940
            self.palette_button[self.orientation + 3].hide()
941
        else:
942
            self.palette_button[self.orientation + 5].hide()
943
            self.palette_button[self.orientation + 3].set_layer(TOP_LAYER)
89cb13a by Walter Bender at 2012-03-28 944
ef4a5f0 by Walter Bender at 2012-02-04 945
    def show_toolbar_palette(self, n, init_only=False, regenerate=False,
946
                             show=True):
2fee6e6 by Walter Bender at 2012-06-23 947
        ''' Show the toolbar palettes, creating them on init_only '''
ffe9fb3 by Walter Bender at 2011-03-19 948
        # If we are running the 0.86+ toolbar, the selectors are already
949
        # created, as toolbar buttons. Otherwise, we need to create them.
d83cb4e by Walter Bender at 2012-10-19 950
        if (not self.running_sugar or not self.activity.has_toolbarbox) and \
c2937d9 by Walter Bender at 2010-08-12 951
           self.selectors == []:
ffe9fb3 by Walter Bender at 2011-03-19 952
            # First, create the selector buttons
953
            self._create_the_selectors()
c2937d9 by Walter Bender at 2010-08-12 954
ffe9fb3 by Walter Bender at 2011-03-19 955
        # Create the empty palettes that we'll then populate with prototypes.
c2937d9 by Walter Bender at 2010-08-12 956
        if self.palette_sprs == []:
ffe9fb3 by Walter Bender at 2011-03-19 957
            self._create_the_empty_palettes()
c2937d9 by Walter Bender at 2010-08-12 958
ffe9fb3 by Walter Bender at 2011-03-19 959
        # At initialization of the program, we don't actually populate
960
        # the palettes.
c2937d9 by Walter Bender at 2010-08-12 961
        if init_only:
962
            return
963
ef4a5f0 by Walter Bender at 2012-02-04 964
        if show:
965
            # Hide the previously displayed palette
966
            self._hide_previous_palette()
967
        else:
968
            save_selected = self.selected_palette
969
            save_previous = self.previous_palette
c2937d9 by Walter Bender at 2010-08-12 970
971
        self.selected_palette = n
dcd7408 by Walter Bender at 2010-10-10 972
        self.previous_palette = self.selected_palette
c2937d9 by Walter Bender at 2010-08-12 973
ffe9fb3 by Walter Bender at 2011-03-19 974
        # Make sure all of the selectors are visible. (We don't need to do
975
        # this for 0.86+ toolbars since the selectors are toolbar buttons.)
db528ec by Walter Bender at 2012-04-09 976
        if show and \
d83cb4e by Walter Bender at 2012-10-19 977
           (not self.running_sugar or not self.activity.has_toolbarbox):
c2937d9 by Walter Bender at 2010-08-12 978
            self.selected_selector = self.selectors[n]
979
            self.selectors[n].set_shape(self.selector_shapes[n][1])
a9fb111 by Walter Bender at 2011-03-05 980
            for i in range(len(palette_blocks)):
c2937d9 by Walter Bender at 2010-08-12 981
                self.selectors[i].set_layer(TAB_LAYER)
982
ef4a5f0 by Walter Bender at 2012-02-04 983
            # Show the palette with the current orientation.
984
            if self.palette_sprs[n][self.orientation] is not None:
db528ec by Walter Bender at 2012-04-09 985
                self.palette_sprs[n][self.orientation].set_layer(
986
                    CATEGORY_LAYER)
89cb13a by Walter Bender at 2012-03-28 987
                self._display_palette_shift_button(n)
c2937d9 by Walter Bender at 2010-08-12 988
ffe9fb3 by Walter Bender at 2011-03-19 989
        # Create 'proto' blocks for each palette entry
8f325e0 by Walter Bender at 2012-02-02 990
        self._create_proto_blocks(n)
ffe9fb3 by Walter Bender at 2011-03-19 991
ef4a5f0 by Walter Bender at 2012-02-04 992
        if show or save_selected == n:
993
            self._layout_palette(n, regenerate=regenerate)
994
        else:
995
            self._layout_palette(n, regenerate=regenerate, show=False)
ffe9fb3 by Walter Bender at 2011-03-19 996
        for blk in self.palettes[n]:
8f325e0 by Walter Bender at 2012-02-02 997
            if blk.get_visibility():
8f68c11 by Walter Bender at 2012-03-24 998
                if hasattr(blk.spr, 'set_layer'):
83420de by Walter Bender at 2012-03-22 999
                    blk.spr.set_layer(PROTO_LAYER)
8f68c11 by Walter Bender at 2012-03-24 1000
                else:
1001
                    debug_output('WARNING: block sprite is None' % (blk.name),
83420de by Walter Bender at 2012-03-22 1002
                                 self.running_sugar)
8f325e0 by Walter Bender at 2012-02-02 1003
            else:
1004
                blk.spr.hide()
98ed32f by Walter Bender at 2013-06-03 1005
        if 'trash' in palette_names and n == palette_names.index('trash'):
ffe9fb3 by Walter Bender at 2011-03-19 1006
            for blk in self.trash_stack:
6c56adb by Walter Bender at 2012-07-05 1007
                # Deprecated
ffe9fb3 by Walter Bender at 2011-03-19 1008
                for gblk in find_group(blk):
1009
                    if gblk.status != 'collapsed':
1010
                        gblk.spr.set_layer(TAB_LAYER)
1011
ef4a5f0 by Walter Bender at 2012-02-04 1012
        if not show:
1013
            if not save_selected == n:
1014
                self._hide_previous_palette(palette=n)
1015
            self.selected_palette = save_selected
1016
            self.previous_palette = save_previous
1017
e4e535a by Walter Bender at 2012-06-23 1018
    def regenerate_palette(self, n):
2fee6e6 by Walter Bender at 2012-06-23 1019
        ''' Regenerate palette (used by some plugins) '''
d83cb4e by Walter Bender at 2012-10-19 1020
        if (not self.running_sugar or not self.activity.has_toolbarbox) and \
e4e535a by Walter Bender at 2012-06-23 1021
           self.selectors == []:
1022
            return
1023
        if self.palette_sprs == []:
1024
            return
1025
1026
        save_selected = self.selected_palette
1027
        save_previous = self.previous_palette
1028
        self.selected_palette = n
1029
        self.previous_palette = self.selected_palette
1030
1031
        if save_selected == n:
1032
            self._layout_palette(n, regenerate=True)
1033
        else:
1034
            self._layout_palette(n, regenerate=True, show=False)
1035
1036
        for blk in self.palettes[n]:
1037
            if blk.get_visibility():
1038
                if hasattr(blk.spr, 'set_layer'):
1039
                    blk.spr.set_layer(PROTO_LAYER)
1040
                else:
1041
                    debug_output('WARNING: block sprite is None' % (blk.name),
1042
                                 self.running_sugar)
1043
            else:
1044
                blk.spr.hide()
1045
1046
        if not save_selected == n:
1047
            self._hide_previous_palette(palette=n)
1048
        self.selected_palette = save_selected
1049
        self.previous_palette = save_previous
1050
89cb13a by Walter Bender at 2012-03-28 1051
    def _display_palette_shift_button(self, n):
1052
        ''' Palettes too wide (or tall) for the screen get a shift button '''
bc0ba2c by Walter Bender at 2013-03-08 1053
        for i in range(4):
1054
            self.palette_button[i + 3].hide()
89cb13a by Walter Bender at 2012-03-28 1055
        if self.palette_sprs[n][self.orientation].type == \
1056
                'category-shift-horizontal':
1057
            self.palette_button[3].set_layer(CATEGORY_LAYER)
1058
        elif self.palette_sprs[n][self.orientation].type == \
1059
                'category-shift-vertical':
1060
            self.palette_button[4].set_layer(CATEGORY_LAYER)
1061
ffe9fb3 by Walter Bender at 2011-03-19 1062
    def _create_the_selectors(self):
cfe8338 by Walter Bender at 2011-10-03 1063
        ''' Create the palette selector buttons: only when running
1064
        old-style Sugar toolbars or from GNOME '''
ffe9fb3 by Walter Bender at 2011-03-19 1065
        svg = SVG()
63cc9bb by Walter Bender at 2013-03-13 1066
        if self.running_sugar:
1067
            x, y = 50, 0  # positioned at the left, top
1068
        else:
1069
            x, y = 0, 0
ffe9fb3 by Walter Bender at 2011-03-19 1070
        for i, name in enumerate(palette_names):
c3f0e8e by Walter Bender at 2011-04-07 1071
            for path in self._icon_paths:
1072
                if os.path.exists(os.path.join(path, '%soff.svg' % (name))):
1073
                    icon_pathname = os.path.join(path, '%soff.svg' % (name))
1074
                    break
1075
            if icon_pathname is not None:
1076
                off_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
1077
            else:
4fff361 by Walter Bender at 2013-05-22 1078
                off_shape = svg_str_to_pixbuf(
1079
                    svg_from_file(
1080
                        os.path.join(
c3f0e8e by Walter Bender at 2011-04-07 1081
                            self._icon_paths[0], 'extrasoff.svg')))
1082
                error_output('Unable to open %soff.svg' % (name),
1083
                             self.running_sugar)
1084
            for path in self._icon_paths:
1085
                if os.path.exists(os.path.join(path, '%son.svg' % (name))):
1086
                    icon_pathname = os.path.join(path, '%son.svg' % (name))
1087
                    break
1088
            if icon_pathname is not None:
1089
                on_shape = svg_str_to_pixbuf(svg_from_file(icon_pathname))
1090
            else:
4fff361 by Walter Bender at 2013-05-22 1091
                on_shape = svg_str_to_pixbuf(
1092
                    svg_from_file(
1093
                        os.path.join(
c3f0e8e by Walter Bender at 2011-04-07 1094
                            self._icon_paths[0], 'extrason.svg')))
1095
                error_output('Unable to open %son.svg' % (name),
1096
                             self.running_sugar)
1097
1098
            self.selector_shapes.append([off_shape, on_shape])
1099
            self.selectors.append(Sprite(self.sprite_list, x, y, off_shape))
ffe9fb3 by Walter Bender at 2011-03-19 1100
            self.selectors[i].type = 'selector'
1101
            self.selectors[i].name = name
1102
            self.selectors[i].set_layer(TAB_LAYER)
1103
            w = self.selectors[i].get_dimensions()[0]
1104
            x += int(w)  # running from left to right
1105
1106
        # Create the toolbar background for the selectors
1107
        self.toolbar_offset = ICON_SIZE
1108
        self.toolbar_spr = Sprite(self.sprite_list, 0, 0,
4fff361 by Walter Bender at 2013-05-22 1109
                                  svg_str_to_pixbuf(svg.toolbar(2 * self.width,
1110
                                                                ICON_SIZE)))
ffe9fb3 by Walter Bender at 2011-03-19 1111
        self.toolbar_spr.type = 'toolbar'
1112
        self.toolbar_spr.set_layer(CATEGORY_LAYER)
1113
1114
    def _create_the_empty_palettes(self):
1115
        ''' Create the empty palettes to be populated by prototype blocks. '''
1116
        if len(self.palettes) == 0:
1117
            for i in range(len(palette_blocks)):
1118
                self.palettes.append([])
1119
1120
        # Create empty palette backgrounds
1121
        for i in palette_names:
1122
            self.palette_sprs.append([None, None])
1123
1124
        # Create the palette orientation button
4fff361 by Walter Bender at 2013-05-22 1125
        self.palette_button.append(
1126
            Sprite(
1127
                self.sprite_list,
1128
                0,
1129
                self.toolbar_offset,
1130
                svg_str_to_pixbuf(
1131
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1132
                        '%s/images/palettehorizontal.svg' % (self.path)))))
4fff361 by Walter Bender at 2013-05-22 1133
        self.palette_button.append(
1134
            Sprite(
1135
                self.sprite_list,
1136
                0,
1137
                self.toolbar_offset,
1138
                svg_str_to_pixbuf(
1139
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1140
                        '%s/images/palettevertical.svg' % (self.path)))))
ffe9fb3 by Walter Bender at 2011-03-19 1141
        self.palette_button[0].name = _('orientation')
1142
        self.palette_button[1].name = _('orientation')
1143
        self.palette_button[0].type = 'palette'
1144
        self.palette_button[1].type = 'palette'
1145
        self.palette_button[self.orientation].set_layer(TAB_LAYER)
1146
        self.palette_button[1 - self.orientation].hide()
1147
1148
        # Create the palette next button
4fff361 by Walter Bender at 2013-05-22 1149
        self.palette_button.append(
1150
            Sprite(
1151
                self.sprite_list, 16,
1152
                self.toolbar_offset,
1153
                svg_str_to_pixbuf(
1154
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1155
                        '%s/images/palettenext.svg' % (self.path)))))
ffe9fb3 by Walter Bender at 2011-03-19 1156
        self.palette_button[2].name = _('next')
1157
        self.palette_button[2].type = 'palette'
1158
        self.palette_button[2].set_layer(TAB_LAYER)
1159
89cb13a by Walter Bender at 2012-03-28 1160
        # Create the palette shift buttons
1161
        dims = self.palette_button[0].get_dimensions()
4fff361 by Walter Bender at 2013-05-22 1162
        self.palette_button.append(
1163
            Sprite(
1164
                self.sprite_list,
1165
                0,
1166
                self.toolbar_offset + dims[1],
1167
                svg_str_to_pixbuf(
1168
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1169
                        '%s/images/palettehshift.svg' % (self.path)))))
4fff361 by Walter Bender at 2013-05-22 1170
        self.palette_button.append(
1171
            Sprite(
1172
                self.sprite_list,
1173
                dims[0],
1174
                self.toolbar_offset,
1175
                svg_str_to_pixbuf(
1176
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1177
                        '%s/images/palettevshift.svg' % (self.path)))))
4fff361 by Walter Bender at 2013-05-22 1178
        self.palette_button.append(
1179
            Sprite(
1180
                self.sprite_list,
1181
                0,
1182
                self.toolbar_offset + dims[1],
1183
                svg_str_to_pixbuf(
1184
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1185
                        '%s/images/palettehshift2.svg' % (self.path)))))
4fff361 by Walter Bender at 2013-05-22 1186
        self.palette_button.append(
1187
            Sprite(
1188
                self.sprite_list,
1189
                dims[0],
1190
                self.toolbar_offset,
1191
                svg_str_to_pixbuf(
1192
                    svg_from_file(
0ee623d by Walter Bender at 2013-07-23 1193
                        '%s/images/palettevshift2.svg' % (self.path)))))
bc0ba2c by Walter Bender at 2013-03-08 1194
        for i in range(4):
1195
            self.palette_button[3 + i].name = _('shift')
1196
            self.palette_button[3 + i].type = 'palette'
1197
            self.palette_button[3 + i].hide()
89cb13a by Walter Bender at 2012-03-28 1198
8f325e0 by Walter Bender at 2012-02-02 1199
    def _create_proto_blocks(self, n):
ffe9fb3 by Walter Bender at 2011-03-19 1200
        ''' Create the protoblocks that will populate a palette. '''
8f325e0 by Walter Bender at 2012-02-02 1201
        # Reload the palette, but reuse the existing blocks
1202
        # If a block doesn't exist, add it
c2937d9 by Walter Bender at 2010-08-12 1203
7a23a41 by Walter Bender at 2012-03-26 1204
        if not n < len(self.palettes):
1205
            debug_output(
4fff361 by Walter Bender at 2013-05-22 1206
                '_create_proto_blocks: palette index %d is out of range' %
1207
                (n), self.running_sugar)
7a23a41 by Walter Bender at 2012-03-26 1208
            return
1209
8f325e0 by Walter Bender at 2012-02-02 1210
        for blk in self.palettes[n]:
1211
            blk.spr.hide()
1212
        old_blocks = self.palettes[n][:]
1213
        self.palettes[n] = []
baf253a by Walter Bender at 2012-03-02 1214
        for name in palette_blocks[n]:
8f325e0 by Walter Bender at 2012-02-02 1215
            found_block = False
1216
            for oblk in old_blocks:
1217
                if oblk.name == name:
1218
                    self.palettes[n].append(oblk)
1219
                    found_block = True
1220
                    break
1221
            if not found_block:
4fff361 by Walter Bender at 2013-05-22 1222
                self.palettes[n].append(
1223
                    Block(self.block_list, self.sprite_list, name, 0, 0,
1224
                          'proto', [], PALETTE_SCALE))
f3f81ec by Walter Bender at 2012-02-04 1225
                if name in hidden_proto_blocks:
baf253a by Walter Bender at 2012-03-02 1226
                    self.palettes[n][-1].set_visibility(False)
83420de by Walter Bender at 2012-03-22 1227
                else:
8f68c11 by Walter Bender at 2012-03-24 1228
                    if hasattr(self.palettes[n][-1].spr, 'set_layer'):
83420de by Walter Bender at 2012-03-22 1229
                        self.palettes[n][-1].spr.set_layer(PROTO_LAYER)
1230
                        self.palettes[n][-1].unhighlight()
8f68c11 by Walter Bender at 2012-03-24 1231
                    else:
4fff361 by Walter Bender at 2013-05-22 1232
                        debug_output('WARNING: block sprite is None' %
1233
                                     (self.palettes[n][-1].name),
1234
                                     self.running_sugar)
8f325e0 by Walter Bender at 2012-02-02 1235
1236
            # Some proto blocks get a skin.
1237
            if name in block_styles['box-style-media']:
baf253a by Walter Bender at 2012-03-02 1238
                self._proto_skin(name + 'small', n, -1)
8f325e0 by Walter Bender at 2012-02-02 1239
            elif name[:8] == 'template':  # Deprecated
baf253a by Walter Bender at 2012-03-02 1240
                self._proto_skin(name[8:], n, -1)
8f325e0 by Walter Bender at 2012-02-02 1241
            elif name[:7] == 'picture':  # Deprecated
baf253a by Walter Bender at 2012-03-02 1242
                self._proto_skin(name[7:], n, -1)
8f325e0 by Walter Bender at 2012-02-02 1243
            elif name in PYTHON_SKIN:
baf253a by Walter Bender at 2012-03-02 1244
                self._proto_skin('pythonsmall', n, -1)
8f325e0 by Walter Bender at 2012-02-02 1245
        return
5b3215c by Walter Bender at 2012-03-26 1246
c2937d9 by Walter Bender at 2010-08-12 1247
    def _hide_toolbar_palette(self):
2fee6e6 by Walter Bender at 2012-06-23 1248
        ''' Hide the toolbar palettes '''
c2937d9 by Walter Bender at 2010-08-12 1249
        self._hide_previous_palette()
d83cb4e by Walter Bender at 2012-10-19 1250
        if not self.running_sugar or not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 1251
            # Hide the selectors
a9fb111 by Walter Bender at 2011-03-05 1252
            for i in range(len(palette_blocks)):
c2937d9 by Walter Bender at 2010-08-12 1253
                self.selectors[i].hide()
85b7829 by Walter Bender at 2011-08-21 1254
        elif self.selected_palette is not None and \
4fff361 by Walter Bender at 2013-05-22 1255
                not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 1256
            self.activity.palette_buttons[self.selected_palette].set_icon(
a9fb111 by Walter Bender at 2011-03-05 1257
                palette_names[self.selected_palette] + 'off')
c2937d9 by Walter Bender at 2010-08-12 1258
ef4a5f0 by Walter Bender at 2012-02-04 1259
    def _hide_previous_palette(self, palette=None):
2fee6e6 by Walter Bender at 2012-06-23 1260
        ''' Hide just the previously viewed toolbar palette '''
ef4a5f0 by Walter Bender at 2012-02-04 1261
        if palette is None:
1262
            palette = self.previous_palette
0d23632 by Walter Bender at 2012-02-04 1263
        # Hide previously selected palette
ef4a5f0 by Walter Bender at 2012-02-04 1264
        if palette is not None:
7a23a41 by Walter Bender at 2012-03-26 1265
            if not palette < len(self.palettes):
1266
                debug_output(
4fff361 by Walter Bender at 2013-05-22 1267
                    '_hide_previous_palette: index %d is out of range' %
1268
                    (palette), self.running_sugar)
7a23a41 by Walter Bender at 2012-03-26 1269
                return
ef4a5f0 by Walter Bender at 2012-02-04 1270
            for proto in self.palettes[palette]:
9ac1353 by Walter Bender at 2011-03-19 1271
                proto.spr.hide()
2f7eb67 by Walter Bender at 2012-03-02 1272
            if self.palette_sprs[palette][self.orientation] is not None:
1273
                self.palette_sprs[palette][self.orientation].hide()
d83cb4e by Walter Bender at 2012-10-19 1274
            if not self.running_sugar or not self.activity.has_toolbarbox:
ef4a5f0 by Walter Bender at 2012-02-04 1275
                self.selectors[palette].set_shape(
1276
                    self.selector_shapes[palette][0])
f3f81ec by Walter Bender at 2012-02-04 1277
            elif palette is not None and palette != self.selected_palette \
4fff361 by Walter Bender at 2013-05-22 1278
                    and not self.activity.has_toolbarbox:
1279
                self.activity.palette_buttons[palette].set_icon(
1280
                    palette_names[palette] + 'off')
98ed32f by Walter Bender at 2013-06-03 1281
            if 'trash' in palette_names and \
1282
                    palette == palette_names.index('trash'):
c2937d9 by Walter Bender at 2010-08-12 1283
                for blk in self.trash_stack:
1284
                    for gblk in find_group(blk):
1285
                        gblk.spr.hide()
1286
1287
    def _horizontal_layout(self, x, y, blocks):
2fee6e6 by Walter Bender at 2012-06-23 1288
        ''' Position prototypes in a horizontal palette. '''
8a742df by Walter Bender at 2011-04-04 1289
        max_w = 0
c2937d9 by Walter Bender at 2010-08-12 1290
        for blk in blocks:
8f325e0 by Walter Bender at 2012-02-02 1291
            if not blk.get_visibility():
1292
                continue
8a742df by Walter Bender at 2011-04-04 1293
            w, h = self._width_and_height(blk)
1294
            if y + h > PALETTE_HEIGHT + self.toolbar_offset:
1295
                x += int(max_w + 3)
c2937d9 by Walter Bender at 2010-08-12 1296
                y = self.toolbar_offset + 3
8a742df by Walter Bender at 2011-04-04 1297
                max_w = 0
1298
            (bx, by) = blk.spr.get_xy()
1299
            dx = x - bx
1300
            dy = y - by
c2937d9 by Walter Bender at 2010-08-12 1301
            for g in find_group(blk):
8a742df by Walter Bender at 2011-04-04 1302
                g.spr.move_relative((int(dx), int(dy)))
cfe8338 by Walter Bender at 2011-10-03 1303
                g.spr.save_xy = g.spr.get_xy()
3a9d89d by Walter Bender at 2011-10-04 1304
                if self.running_sugar and not self.hw in [XO1]:
cfe8338 by Walter Bender at 2011-10-03 1305
                    g.spr.move_relative((self.activity.hadj_value,
8f325e0 by Walter Bender at 2012-02-02 1306
                                         self.activity.vadj_value))
8a742df by Walter Bender at 2011-04-04 1307
            y += int(h + 3)
1308
            if w > max_w:
1309
                max_w = w
1310
        return x, y, max_w
c2937d9 by Walter Bender at 2010-08-12 1311
1312
    def _vertical_layout(self, x, y, blocks):
2fee6e6 by Walter Bender at 2012-06-23 1313
        ''' Position prototypes in a vertical palette. '''
8a742df by Walter Bender at 2011-04-04 1314
        row = []
1315
        row_w = 0
1316
        max_h = 0
8f325e0 by Walter Bender at 2012-02-02 1317
        for blk in blocks:
1318
            if not blk.get_visibility():
1319
                continue
1320
            w, h = self._width_and_height(blk)
8a742df by Walter Bender at 2011-04-04 1321
            if x + w > PALETTE_WIDTH:
c2937d9 by Walter Bender at 2010-08-12 1322
                # Recenter row.
8a742df by Walter Bender at 2011-04-04 1323
                dx = int((PALETTE_WIDTH - row_w) / 2)
1324
                for r in row:
1325
                    for g in find_group(r):
1326
                        g.spr.move_relative((dx, 0))
cfe8338 by Walter Bender at 2011-10-03 1327
                        g.spr.save_xy = (g.spr.save_xy[0] + dx,
1328
                                         g.spr.save_xy[1])
8a742df by Walter Bender at 2011-04-04 1329
                row = []
1330
                row_w = 0
c2937d9 by Walter Bender at 2010-08-12 1331
                x = 4
8a742df by Walter Bender at 2011-04-04 1332
                y += int(max_h + 3)
1333
                max_h = 0
8f325e0 by Walter Bender at 2012-02-02 1334
            row.append(blk)
8a742df by Walter Bender at 2011-04-04 1335
            row_w += (4 + w)
8f325e0 by Walter Bender at 2012-02-02 1336
            (bx, by) = blk.spr.get_xy()
8a742df by Walter Bender at 2011-04-04 1337
            dx = int(x - bx)
1338
            dy = int(y - by)
8f325e0 by Walter Bender at 2012-02-02 1339
            for g in find_group(blk):
8a742df by Walter Bender at 2011-04-04 1340
                g.spr.move_relative((dx, dy))
cfe8338 by Walter Bender at 2011-10-03 1341
                g.spr.save_xy = g.spr.get_xy()
3a9d89d by Walter Bender at 2011-10-04 1342
                if self.running_sugar and not self.hw in [XO1]:
cfe8338 by Walter Bender at 2011-10-03 1343
                    g.spr.move_relative((self.activity.hadj_value,
8f325e0 by Walter Bender at 2012-02-02 1344
                                         self.activity.vadj_value))
8a742df by Walter Bender at 2011-04-04 1345
            x += int(w + 4)
1346
            if h > max_h:
1347
                max_h = h
c2937d9 by Walter Bender at 2010-08-12 1348
        # Recenter last row.
8a742df by Walter Bender at 2011-04-04 1349
        dx = int((PALETTE_WIDTH - row_w) / 2)
1350
        for r in row:
1351
            for g in find_group(r):
1352
                g.spr.move_relative((dx, 0))
cfe8338 by Walter Bender at 2011-10-03 1353
                g.spr.save_xy = (g.spr.save_xy[0] + dx, g.spr.save_xy[1])
8a742df by Walter Bender at 2011-04-04 1354
        return x, y, max_h
c2937d9 by Walter Bender at 2010-08-12 1355
ef4a5f0 by Walter Bender at 2012-02-04 1356
    def _layout_palette(self, n, regenerate=False, show=True):
2fee6e6 by Walter Bender at 2012-06-23 1357
        ''' Layout prototypes in a palette. '''
c2937d9 by Walter Bender at 2010-08-12 1358
        if n is not None:
1359
            if self.orientation == HORIZONTAL_PALETTE:
11333ce by Walter Bender at 2013-05-22 1360
                x, y = _BUTTON_SIZE, self.toolbar_offset + _MARGIN
8a742df by Walter Bender at 2011-04-04 1361
                x, y, max_w = self._horizontal_layout(x, y, self.palettes[n])
98ed32f by Walter Bender at 2013-06-03 1362
                if 'trash' in palette_names and \
1363
                        n == palette_names.index('trash'):
8a742df by Walter Bender at 2011-04-04 1364
                    x, y, max_w = self._horizontal_layout(x + max_w, y,
1365
                                                          self.trash_stack)
11333ce by Walter Bender at 2013-05-22 1366
                w = x + max_w + _BUTTON_SIZE + _MARGIN
8a742df by Walter Bender at 2011-04-04 1367
                self._make_palette_spr(n, 0, self.toolbar_offset,
1368
                                       w, PALETTE_HEIGHT, regenerate)
ef4a5f0 by Walter Bender at 2012-02-04 1369
                if show:
ccbce87 by Walter Bender at 2013-02-28 1370
                    self.palette_button[2].move(
11333ce by Walter Bender at 2013-05-22 1371
                        (w - _BUTTON_SIZE, self.toolbar_offset))
bc0ba2c by Walter Bender at 2013-03-08 1372
                    self.palette_button[4].move(
11333ce by Walter Bender at 2013-05-22 1373
                        (_BUTTON_SIZE, self.toolbar_offset))
bc0ba2c by Walter Bender at 2013-03-08 1374
                    self.palette_button[6].move(
11333ce by Walter Bender at 2013-05-22 1375
                        (_BUTTON_SIZE, self.toolbar_offset))
c2937d9 by Walter Bender at 2010-08-12 1376
            else:
11333ce by Walter Bender at 2013-05-22 1377
                x, y = _MARGIN, self.toolbar_offset + _BUTTON_SIZE + _MARGIN
8a742df by Walter Bender at 2011-04-04 1378
                x, y, max_h = self._vertical_layout(x, y, self.palettes[n])
98ed32f by Walter Bender at 2013-06-03 1379
                if 'trash' in palette_names and \
1380
                        n == palette_names.index('trash'):
8a742df by Walter Bender at 2011-04-04 1381
                    x, y, max_h = self._vertical_layout(x, y + max_h,
1382
                                                        self.trash_stack)
11333ce by Walter Bender at 2013-05-22 1383
                h = y + max_h + _BUTTON_SIZE + _MARGIN - self.toolbar_offset
8a742df by Walter Bender at 2011-04-04 1384
                self._make_palette_spr(n, 0, self.toolbar_offset,
1385
                                       PALETTE_WIDTH, h, regenerate)
ef4a5f0 by Walter Bender at 2012-02-04 1386
                if show:
11333ce by Walter Bender at 2013-05-22 1387
                    self.palette_button[2].move((PALETTE_WIDTH - _BUTTON_SIZE,
ef4a5f0 by Walter Bender at 2012-02-04 1388
                                                 self.toolbar_offset))
4fff361 by Walter Bender at 2013-05-22 1389
                    self.palette_button[3].move(
11333ce by Walter Bender at 2013-05-22 1390
                        (0, self.toolbar_offset + _BUTTON_SIZE))
4fff361 by Walter Bender at 2013-05-22 1391
                    self.palette_button[5].move(
11333ce by Walter Bender at 2013-05-22 1392
                        (0, self.toolbar_offset + _BUTTON_SIZE))
ef4a5f0 by Walter Bender at 2012-02-04 1393
            if show:
db528ec by Walter Bender at 2012-04-09 1394
                self.palette_button[2].save_xy = \
1395
                    self.palette_button[2].get_xy()
3a9d89d by Walter Bender at 2011-10-04 1396
                if self.running_sugar and not self.hw in [XO1]:
cfe8338 by Walter Bender at 2011-10-03 1397
                    self.palette_button[2].move_relative(
1398
                        (self.activity.hadj_value, self.activity.vadj_value))
db528ec by Walter Bender at 2012-04-09 1399
                self.palette_sprs[n][self.orientation].set_layer(
1400
                    CATEGORY_LAYER)
89cb13a by Walter Bender at 2012-03-28 1401
                self._display_palette_shift_button(n)
c2937d9 by Walter Bender at 2010-08-12 1402
8a742df by Walter Bender at 2011-04-04 1403
    def _make_palette_spr(self, n, x, y, w, h, regenerate=False):
1404
        ''' Make the background for the palette. '''
1405
        if regenerate and not self.palette_sprs[n][self.orientation] is None:
1406
            self.palette_sprs[n][self.orientation].hide()
1407
            self.palette_sprs[n][self.orientation] = None
1408
        if self.palette_sprs[n][self.orientation] is None:
1409
            svg = SVG()
1410
            self.palette_sprs[n][self.orientation] = \
1411
                Sprite(self.sprite_list, x, y, svg_str_to_pixbuf(
1412
                    svg.palette(w, h)))
cfe8338 by Walter Bender at 2011-10-03 1413
            self.palette_sprs[n][self.orientation].save_xy = (x, y)
3a9d89d by Walter Bender at 2011-10-04 1414
            if self.running_sugar and not self.hw in [XO1]:
cfe8338 by Walter Bender at 2011-10-03 1415
                self.palette_sprs[n][self.orientation].move_relative(
1416
                    (self.activity.hadj_value, self.activity.vadj_value))
89cb13a by Walter Bender at 2012-03-28 1417
            if self.orientation == 0 and w > self.width:
1418
                self.palette_sprs[n][self.orientation].type = \
1419
                    'category-shift-horizontal'
1420
            elif self.orientation == 1 and h > self.height - ICON_SIZE:
1421
                self.palette_sprs[n][self.orientation].type = \
1422
                    'category-shift-vertical'
1423
            else:
1424
                self.palette_sprs[n][self.orientation].type = 'category'
98ed32f by Walter Bender at 2013-06-03 1425
            if 'trash' in palette_names and \
1426
                    n == palette_names.index('trash'):
8a742df by Walter Bender at 2011-04-04 1427
                svg = SVG()
1428
                self.palette_sprs[n][self.orientation].set_shape(
1429
                    svg_str_to_pixbuf(svg.palette(w, h)))
1430
c2937d9 by Walter Bender at 2010-08-12 1431
    def _buttonpress_cb(self, win, event):
2fee6e6 by Walter Bender at 2012-06-23 1432
        ''' Button press '''
c2937d9 by Walter Bender at 2010-08-12 1433
        self.window.grab_focus()
1434
        x, y = xy(event)
1435
        self.mouse_flag = 1
1436
        self.mouse_x = x
1437
        self.mouse_y = y
dcd7408 by Walter Bender at 2010-10-10 1438
        self.button_press(event.get_state() & gtk.gdk.CONTROL_MASK, x, y)
c2937d9 by Walter Bender at 2010-08-12 1439
        return True
1440
f649ef8 by Walter Bender at 2010-08-18 1441
    def button_press(self, mask, x, y):
112a8d7 by Walter Bender at 2013-05-01 1442
        if self.running_sugar:
1443
            self._show_unfullscreen_button()
1444
5dc2ede by Walter Bender at 2012-01-05 1445
        # Find out what was clicked
1446
        spr = self.sprite_list.find_sprite((x, y))
1447
1d04f39 by Walter Bender at 2013-02-10 1448
        if self.running_blocks:
1449
            if spr is not None:
1450
                blk = self.block_list.spr_to_block(spr)
1451
                if blk is not None:
bc09b50 by Walter Bender at 2013-08-21 1452
                    # Make sure stop button is visible
1453
                    if self.running_sugar:
1454
                        self.activity.stop_turtle_button.set_icon("stopiton")
1455
                        self.activity.stop_turtle_button.set_tooltip(
1456
                            _('Stop turtle'))
1457
                    elif self.interactive_mode:
1458
                        self.toolbar_shapes['stopiton'].set_layer(TAB_LAYER)
1d04f39 by Walter Bender at 2013-02-10 1459
                    self.showlabel('status',
1460
                                   label=_('Please hit the Stop Button \
1461
before making changes to your Turtle Blocks program'))
1462
                    self._autohide_shape = True
1463
                    return True
1464
1465
        self.block_operation = 'click'
1466
1467
        self._unselect_all_blocks()
1468
        self._hide_status_layer(spr)
1469
1470
        self.dx = 0
1471
        self.dy = 0
1472
        self.dragging_canvas[1] = x
1473
        self.dragging_canvas[2] = y
1474
        if spr is None:
f5a2055 by Walter Bender at 2013-03-01 1475
            if not self.running_blocks and not self.hw in [XO1]:
1d04f39 by Walter Bender at 2013-02-10 1476
                self.dragging_canvas[0] = True
2ca3c1f by Walter Bender at 2013-02-22 1477
                self.dragging_counter = 0
1478
                self.dragging_dx = 0
1479
                self.dragging_dy = 0
1d04f39 by Walter Bender at 2013-02-10 1480
            return True
1481
        self.dragging_canvas[0] = False
1482
        self.selected_spr = spr
1483
1484
        if self._look_for_a_blk(spr, x, y):
1485
            return True
1486
        elif self._look_for_a_turtle(spr, x, y):
1487
            return True
1488
        elif self._check_for_anything_else(spr, x, y):
1489
            return True
1490
1491
    def _unselect_all_blocks(self):
c2937d9 by Walter Bender at 2010-08-12 1492
        # Unselect things that may have been selected earlier
1493
        if self.selected_blk is not None:
e93a1fd by Walter Bender at 2012-11-11 1494
            if self._action_name(self.selected_blk, hat=True):
52b0e32 by Walter Bender at 2012-06-16 1495
                if self.selected_blk.values[0] == _('action'):
1496
                    self._new_stack_block(self.selected_blk.spr.labels[0])
1497
                self._update_action_names(self.selected_blk.spr.labels[0])
1498
            elif self._box_name(self.selected_blk, storein=True):
1499
                if self.selected_blk.values[0] == _('my box'):
223c3f8 by Walter Bender at 2012-07-25 1500
                    self._new_storein_block(self.selected_blk.spr.labels[0])
52b0e32 by Walter Bender at 2012-06-16 1501
                    self._new_box_block(self.selected_blk.spr.labels[0])
223c3f8 by Walter Bender at 2012-07-25 1502
                self._update_storein_names(self.selected_blk.spr.labels[0])
52b0e32 by Walter Bender at 2012-06-16 1503
                self._update_box_names(self.selected_blk.spr.labels[0])
684ea24 by Walter Bender at 2012-06-13 1504
            # Un-highlight any blocks in the stack
1505
            grp = find_group(self.selected_blk)
1506
            for blk in grp:
1507
                if blk.status != 'collapsed':
1508
                    blk.unhighlight()
c2937d9 by Walter Bender at 2010-08-12 1509
            self._unselect_block()
64384f5 by Walter Bender at 2012-06-13 1510
            if self.running_sugar and self._sharing and \
1511
               hasattr(self.activity, 'share_button'):
1512
                self.activity.share_button.set_tooltip(
1513
                    _('Select blocks to share'))
c2937d9 by Walter Bender at 2010-08-12 1514
        self.selected_turtle = None
7b697bd by Walter Bender at 2010-08-21 1515
1d04f39 by Walter Bender at 2013-02-10 1516
    def _hide_status_layer(self, spr):
8d09405 by Walter Bender at 2012-10-19 1517
        # Almost always hide the status layer on a click
1518
        if self._autohide_shape and self.status_spr is not None:
1519
            self.status_spr.hide()
1520
        elif spr == self.status_spr:
c2937d9 by Walter Bender at 2010-08-12 1521
            self.status_spr.hide()
8d09405 by Walter Bender at 2012-10-19 1522
            self._autohide_shape = True
c2937d9 by Walter Bender at 2010-08-12 1523
1d04f39 by Walter Bender at 2013-02-10 1524
    def _look_for_a_blk(self, spr, x, y):
c2937d9 by Walter Bender at 2010-08-12 1525
        # From the sprite at x, y, look for a corresponding block
1526
        blk = self.block_list.spr_to_block(spr)
ea57633 by Walter Bender at 2012-06-30 1527
        ''' If we were copying and didn't click on a block... '''
6553d94 by Walter Bender at 2013-05-08 1528
        if self.copying_blocks or self.sharing_blocks or self.saving_blocks:
ea57633 by Walter Bender at 2012-06-30 1529
            if blk is None or blk.type != 'block':
6553d94 by Walter Bender at 2013-05-08 1530
                self.parent.get_window().set_cursor(
1531
                    gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
1532
                self.copying_blocks = False
1533
                self.sharing_blocks = False
1534
                self.saving_blocks = False
2467422 by Walter Bender at 2013-05-09 1535
        elif self.deleting_blocks:
1536
            if blk is None or blk.type != 'proto':
1537
                self.parent.get_window().set_cursor(
1538
                    gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
1539
                self.deleting_blocks = False
c2937d9 by Walter Bender at 2010-08-12 1540
        if blk is not None:
1541
            if blk.type == 'block':
1542
                self.selected_blk = blk
1543
                self._block_pressed(x, y, blk)
1544
            elif blk.type == 'trash':
1545
                self._restore_from_trash(find_top_block(blk))
1546
            elif blk.type == 'proto':
2467422 by Walter Bender at 2013-05-09 1547
                if self.deleting_blocks:
0ff6b1c by Walter Bender at 2013-05-09 1548
                    if 'myblocks' in palette_names and \
1549
                            self.selected_palette == \
2467422 by Walter Bender at 2013-05-09 1550
                            palette_names.index('myblocks'):
1551
                        self._delete_stack_alert(blk)
1552
                    self.parent.get_window().set_cursor(
1553
                        gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
1554
                    self.deleting_blocks = False
1555
                elif blk.name == 'restoreall':
c2937d9 by Walter Bender at 2010-08-12 1556
                    self._restore_all_from_trash()
1557
                elif blk.name == 'restore':
28be071 by Walter Bender at 2012-07-31 1558
                    self.restore_latest_from_trash()
c2937d9 by Walter Bender at 2010-08-12 1559
                elif blk.name == 'empty':
1560
                    self._empty_trash()
ac66903 by Walter Bender at 2011-05-07 1561
                elif blk.name == 'trashall':
1562
                    for b in self.just_blocks():
1563
                        if b.type != 'trash':
4f3f27b by Walter Bender at 2012-11-07 1564
                            if b.name == 'start':  # Don't trash start block
1565
                                b1 = b.connections[-1]
1566
                                if b1 is not None:
1567
                                    b.connections[-1] = None
1568
                                    b1.connections[0] = None
1569
                                    self._put_in_trash(b1)
1570
                            else:
1571
                                self._put_in_trash(find_top_block(b))
ccbce87 by Walter Bender at 2013-02-28 1572
                    self.show_toolbar_palette(palette_names.index('trash'),
4fff361 by Walter Bender at 2013-05-22 1573
                                              regenerate=True)
7680eb3 by Walter Bender at 2010-09-21 1574
                elif blk.name in MACROS:
bafc3af by Walter Bender at 2012-07-21 1575
                    self.new_macro(blk.name, x + 20, y + 20)
c2937d9 by Walter Bender at 2010-08-12 1576
                else:
cdc5a20 by Walter Bender at 2012-06-16 1577
                    defaults = None
1578
                    name = blk.name
25320df by Walter Bender at 2010-10-19 1579
                    # You can only have one instance of some blocks
1580
                    if blk.name in ['start', 'hat1', 'hat2']:
36a3a64 by Walter Bender at 2010-10-20 1581
                        if len(self.block_list.get_similar_blocks(
1582
                                'block', blk.name)) > 0:
1d5319b by Walter Bender at 2010-11-06 1583
                            self.showlabel('dupstack')
25320df by Walter Bender at 2010-10-19 1584
                            return True
d9d5552 by Walter Bender at 2012-07-19 1585
                    # We need to check to see if there is already a
1586
                    # similarly default named stack
06e1ef7 by Walter Bender at 2013-01-04 1587
                    elif blk.name == 'hat':
d9d5552 by Walter Bender at 2012-07-19 1588
                        similars = self.block_list.get_similar_blocks(
1589
                            'block', blk.name)
d0d5657 by Walter Bender at 2012-09-01 1590
                        # First look for a hat with _('action') as its label
1591
                        found_the_action_block = False
1592
                        bname = _('action')
530ac92 by Walter Bender at 2013-05-05 1593
                        if isinstance(bname, unicode):
d0d5657 by Walter Bender at 2012-09-01 1594
                            bname = bname.encode('ascii', 'replace')
1595
                        for sblk in similars:
1596
                            cblk = sblk.connections[1]
1597
                            if cblk is not None:
1598
                                blabel = cblk.spr.labels[0]
530ac92 by Walter Bender at 2013-05-05 1599
                                if isinstance(blabel, unicode):
d0d5657 by Walter Bender at 2012-09-01 1600
                                    blabel = blabel.encode('ascii', 'replace')
1601
                                if bname == blabel:
1602
                                    found_the_action_block = True
1603
                        # If there is an action block in use, change the name
1604
                        if len(similars) > 0 and found_the_action_block:
d9d5552 by Walter Bender at 2012-07-19 1605
                            defaults = [_('action')]
1606
                            if self._find_proto_name('stack', defaults[0]):
679bf36 by Walter Bender at 2012-07-25 1607
                                defaults[0] = increment_name(defaults[0])
4fff361 by Walter Bender at 2013-05-22 1608
                                while self._find_proto_name('stack_%s' %
1609
                                                            (defaults[0]),
1610
                                                            defaults[0]):
679bf36 by Walter Bender at 2012-07-25 1611
                                    defaults[0] = increment_name(defaults[0])
d9d5552 by Walter Bender at 2012-07-19 1612
                                self._new_stack_block(defaults[0])
52b0e32 by Walter Bender at 2012-06-16 1613
                    # If we autogenerated a stack prototype, we need
1614
                    # to change its name from 'stack_foo' to 'stack'
1615
                    elif blk.name[0:6] == 'stack_':
1616
                        defaults = [blk.name[6:]]
1617
                        name = 'stack'
1618
                    # If we autogenerated a box prototype, we need
1619
                    # to change its name from 'box_foo' to 'box'
1620
                    elif blk.name[0:4] == 'box_':
1621
                        defaults = [blk.name[4:]]
1622
                        name = 'box'
223c3f8 by Walter Bender at 2012-07-25 1623
                    # If we autogenerated a storein prototype, we need
1624
                    # to change its name from 'storein_foo' to 'foo'
1625
                    # and label[1] from foo to box
1626
                    elif blk.name[0:8] == 'storein_':
1627
                        defaults = [blk.name[8:], 100]
1628
                        name = 'storein'
06e1ef7 by Walter Bender at 2013-01-04 1629
                    # storein my_box gets incremented
1630
                    elif blk.name == 'storein':
1631
                        defaults = [_('my box'), 100]
1632
                        defaults[0] = increment_name(defaults[0])
4fff361 by Walter Bender at 2013-05-22 1633
                        while self._find_proto_name('storein_%s' %
1634
                                                    (defaults[0]),
1635
                                                    defaults[0]):
06e1ef7 by Walter Bender at 2013-01-04 1636
                            defaults[0] = increment_name(defaults[0])
1637
                        self._new_storein_block(defaults[0])
1638
                        self._new_box_block(defaults[0])
1639
                        name = 'storein'
77630cb by Walter Bender at 2011-02-25 1640
                    # You cannot mix and match sensor blocks
1d5319b by Walter Bender at 2010-11-06 1641
                    elif blk.name in ['sound', 'volume', 'pitch']:
1642
                        if len(self.block_list.get_similar_blocks(
bb359af by Walter Bender at 2011-12-05 1643
                                'block', ['resistance', 'voltage',
1644
                                          'resistance2', 'voltage2'])) > 0:
1d5319b by Walter Bender at 2010-11-06 1645
                            self.showlabel('incompatible')
1646
                            return True
bb359af by Walter Bender at 2011-12-05 1647
                    elif blk.name in ['resistance', 'voltage',
1648
                                      'resistance2', 'voltage2']:
1d5319b by Walter Bender at 2010-11-06 1649
                        if len(self.block_list.get_similar_blocks(
1650
                                'block', ['sound', 'volume', 'pitch'])) > 0:
1651
                            self.showlabel('incompatible')
1652
                            return True
bb359af by Walter Bender at 2011-12-05 1653
                        if blk.name in ['resistance', 'resistance2']:
1d5319b by Walter Bender at 2010-11-06 1654
                            if len(self.block_list.get_similar_blocks(
bb359af by Walter Bender at 2011-12-05 1655
                                    'block', ['voltage', 'voltage2'])) > 0:
1d5319b by Walter Bender at 2010-11-06 1656
                                self.showlabel('incompatible')
1657
                                return True
bb359af by Walter Bender at 2011-12-05 1658
                        elif blk.name in ['voltage', 'voltage2']:
1d5319b by Walter Bender at 2010-11-06 1659
                            if len(self.block_list.get_similar_blocks(
bb359af by Walter Bender at 2011-12-05 1660
                                    'block', ['resistance',
1661
                                              'resistance2'])) > 0:
1d5319b by Walter Bender at 2010-11-06 1662
                                self.showlabel('incompatible')
1663
                                return True
c2937d9 by Walter Bender at 2010-08-12 1664
                    blk.highlight()
cdc5a20 by Walter Bender at 2012-06-16 1665
                    self._new_block(name, x, y, defaults=defaults)
c2937d9 by Walter Bender at 2010-08-12 1666
                    blk.unhighlight()
1667
            return True
1d04f39 by Walter Bender at 2013-02-10 1668
        return False
c2937d9 by Walter Bender at 2010-08-12 1669
1442d65 by Walter Bender at 2013-05-09 1670
    def _save_stack_alert(self, name, data, macro_path):
1671
        if self.running_sugar:
1672
            from sugar.graphics.alert import Alert
1673
            from sugar.graphics.icon import Icon
1674
1675
            alert = Alert()
1676
            alert.props.title = _('Save stack')
1677
            alert.props.msg = _('Really overwrite stack?')
1678
1679
            cancel_icon = Icon(icon_name='dialog-cancel')
1680
            alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'),
1681
                             cancel_icon)
1682
            stop_icon = Icon(icon_name='dialog-ok')
4fff361 by Walter Bender at 2013-05-22 1683
            alert.add_button(gtk.RESPONSE_OK, '%s %s' %
1684
                             (_('Overwrite stack'), name), stop_icon)
1442d65 by Walter Bender at 2013-05-09 1685
1686
            self.activity.add_alert(alert)
1687
            alert.connect('response',
1688
                          self._overwrite_stack_dialog_response_cb, data,
1689
                          macro_path)
1690
        else:
1691
            msg = _('Really overwrite stack?')
1692
            dialog = gtk.MessageDialog(self.parent, 0, gtk.MESSAGE_WARNING,
1693
                                       gtk.BUTTONS_OK_CANCEL, msg)
1694
            dialog.set_title('%s %s' % (_('Overwrite stack'), name))
1695
            answer = dialog.run()
1696
            dialog.destroy()
1697
            if answer == gtk.RESPONSE_OK:
1698
                self._save_stack(data, macro_path)
1699
1700
    def _overwrite_stack_dialog_response_cb(self, alert, response_id,
1701
                                            data, macro_path):
1702
        self.activity.remove_alert(alert)
1703
        if response_id == gtk.RESPONSE_OK:
1704
            self._save_stack(data, macro_path)
1705
1706
    def _save_stack(self, data, macro_path):
1707
        data_to_file(data, macro_path)
1708
2467422 by Walter Bender at 2013-05-09 1709
    def _delete_stack_alert(self, blk):
1710
        if self.running_sugar:
1711
            from sugar.graphics.alert import Alert
1712
            from sugar.graphics.icon import Icon
1713
1714
            alert = Alert()
1715
            alert.props.title = _('Delete stack')
1716
            alert.props.msg = _('Really delete stack?')
1717
1718
            cancel_icon = Icon(icon_name='dialog-cancel')
1719
            alert.add_button(gtk.RESPONSE_CANCEL, _('Cancel'),
1720
                             cancel_icon)
1721
            stop_icon = Icon(icon_name='dialog-ok')
4fff361 by Walter Bender at 2013-05-22 1722
            alert.add_button(gtk.RESPONSE_OK, '%s %s' %
1723
                             (_('Delete stack'), blk.spr.labels[0]), stop_icon)
2467422 by Walter Bender at 2013-05-09 1724
1725
            self.activity.add_alert(alert)
1726
            alert.connect('response', self._delete_stack_dialog_response_cb,
1727
                          blk)
1728
        else:
1729
            msg = _('Really delete stack?')
1730
            dialog = gtk.MessageDialog(self.parent, 0, gtk.MESSAGE_WARNING,
1731
                                       gtk.BUTTONS_OK_CANCEL, msg)
1732
            dialog.set_title('%s %s' % (_('Delete stack'), blk.spr.labels[0]))
1733
            answer = dialog.run()
1734
            dialog.destroy()
1735
            if answer == gtk.RESPONSE_OK:
1736
                self._delete_stack(blk)
1737
1738
    def _delete_stack_dialog_response_cb(self, alert, response_id, blk):
1739
        self.activity.remove_alert(alert)
1740
        if response_id == gtk.RESPONSE_OK:
1741
            self._delete_stack(blk)
1742
1743
    def _delete_stack(self, blk):
1744
            name = blk.spr.labels[0]
1745
            error_output('deleting proto: clicked on %s %s' % (blk.name, name),
1746
                         self.running_sugar)
1747
            macro_path = os.path.join(self.macros_path, '%s.tb' % (name))
1748
            if os.path.exists(macro_path):
1749
                try:
1750
                    os.remove(macro_path)
1751
                except Exception, e:
ed2c583 by Walter Bender at 2013-05-22 1752
                    error_output('Could not remove macro %s: %s' %
1753
                                 (macro_path, e))
2467422 by Walter Bender at 2013-05-09 1754
                    return
1755
                i = palette_names.index('myblocks')
1756
                palette_blocks[i].remove(blk.name)
1757
                for pblk in self.palettes[i]:
1758
                    if pblk.name == blk.name:
1759
                        pblk.spr.hide()
1760
                        self.palettes[i].remove(pblk)
1761
                        break
1762
                self.show_toolbar_palette(i, regenerate=True)
1763
1d04f39 by Walter Bender at 2013-02-10 1764
    def _look_for_a_turtle(self, spr, x, y):
c2937d9 by Walter Bender at 2010-08-12 1765
        # Next, look for a turtle
0dda146 by Walter Bender at 2013-06-25 1766
        turtle = self.turtles.spr_to_turtle(spr)
1767
        if turtle is not None:
e1bccd2 by Walter Bender at 2011-03-13 1768
            # If turtle is shared, ignore click
0dda146 by Walter Bender at 2013-06-25 1769
            if self.remote_turtle(turtle.get_name()):
e39c136 by Walter Bender at 2011-03-13 1770
                return True
0dda146 by Walter Bender at 2013-06-25 1771
            self.selected_turtle = turtle
1772
            self.turtles.set_turtle(self.turtles.get_turtle_key(turtle))
c2937d9 by Walter Bender at 2010-08-12 1773
            self._turtle_pressed(x, y)
f5a2055 by Walter Bender at 2013-03-01 1774
            self.update_counter = 0
c2937d9 by Walter Bender at 2010-08-12 1775
            return True
1d04f39 by Walter Bender at 2013-02-10 1776
        return False
c2937d9 by Walter Bender at 2010-08-12 1777
1d04f39 by Walter Bender at 2013-02-10 1778
    def _check_for_anything_else(self, spr, x, y):
c2937d9 by Walter Bender at 2010-08-12 1779
        # Finally, check for anything else
1780
        if hasattr(spr, 'type'):
0150810 by Walter Bender at 2011-11-03 1781
            if spr.type == 'selector':
c2937d9 by Walter Bender at 2010-08-12 1782
                self._select_category(spr)
89cb13a by Walter Bender at 2012-03-28 1783
            elif spr.type in ['category', 'category-shift-horizontal',
1784
                              'category-shift-vertical']:
c2937d9 by Walter Bender at 2010-08-12 1785
                if hide_button_hit(spr, x, y):
1786
                    self.hideshow_palette(False)
1787
            elif spr.type == 'palette':
1788
                if spr.name == _('next'):
1789
                    i = self.selected_palette + 1
a9fb111 by Walter Bender at 2011-03-05 1790
                    if i == len(palette_names):
c2937d9 by Walter Bender at 2010-08-12 1791
                        i = 0
d83cb4e by Walter Bender at 2012-10-19 1792
                    if not self.running_sugar or \
4b1f02e by Walter Bender at 2011-03-05 1793
                       not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 1794
                        self._select_category(self.selectors[i])
1795
                    else:
85b7829 by Walter Bender at 2011-08-21 1796
                        if self.selected_palette is not None and \
4fff361 by Walter Bender at 2013-05-22 1797
                                not self.activity.has_toolbarbox:
c2937d9 by Walter Bender at 2010-08-12 1798
                            self.activity.palette_buttons[
1799
                                self.selected_palette].set_icon(
4fff361 by Walter Bender at 2013-05-22 1800
                                    palette_names[self.selected_palette] +
1801
                                    'off')
dd8fd4b by Walter Bender at 2011-10-03 1802
                        else:
1803
                            # select radio button associated with this palette
1804
                            self.activity.palette_buttons[i].set_active(True)
85b7829 by Walter Bender at 2011-08-21 1805
                        if not self.activity.has_toolbarbox:
1806
                            self.activity.palette_buttons[i].set_icon(
1807
                                palette_names[i] + 'on')
c2937d9 by Walter Bender at 2010-08-12 1808
                        self.show_palette(i)
89cb13a by Walter Bender at 2012-03-28 1809
                elif spr.name == _('shift'):
1810
                    self._shift_toolbar_palette(self.selected_palette)
c2937d9 by Walter Bender at 2010-08-12 1811
                else:
1812
                    self.orientation = 1 - self.orientation
1813
                    self.palette_button[self.orientation].set_layer(TAB_LAYER)
1814
                    self.palette_button[1 - self.orientation].hide()
1815
                    self.palette_sprs[self.selected_palette][
dcd7408 by Walter Bender at 2010-10-10 1816
                        1 - self.orientation].hide()
89e9f18 by Walter Bender at 2011-03-19 1817
                    self._layout_palette(self.selected_palette)
c2937d9 by Walter Bender at 2010-08-12 1818
                    self.show_palette(self.selected_palette)
1819
            elif spr.type == 'toolbar':
1820
                self._select_toolbar_button(spr)
1d04f39 by Walter Bender at 2013-02-10 1821
        return False
c2937d9 by Walter Bender at 2010-08-12 1822
52b0e32 by Walter Bender at 2012-06-16 1823
    def _update_action_names(self, name):
2fee6e6 by Walter Bender at 2012-06-23 1824
        ''' change the label on action blocks of the same name '''
530ac92 by Walter Bender at 2013-05-05 1825
        if isinstance(name, (float, int)):
585cac9 by Walter Bender at 2012-07-18 1826
            return
530ac92 by Walter Bender at 2013-05-05 1827
        if isinstance(name, unicode):
d9d5552 by Walter Bender at 2012-07-19 1828
            name = name.encode('ascii', 'replace')
52b0e32 by Walter Bender at 2012-06-16 1829
        for blk in self.just_blocks():
1830
            if self._action_name(blk, hat=False):
1831
                if blk.spr.labels[0] == self._saved_action_name:
1832
                    blk.spr.labels[0] = name
1833
                    blk.values[0] = name
db6f971 by Walter Bender at 2013-01-25 1834
                if blk.status == 'collapsed':
1835
                    blk.spr.hide()
ca5dc29 by Walter Bender at 2013-01-25 1836
                else:
1837
                    blk.spr.set_layer(BLOCK_LAYER)
144d719 by Walter Bender at 2012-06-23 1838
        self._update_proto_name(name, 'stack_%s' % (self._saved_action_name),
cdc5a20 by Walter Bender at 2012-06-16 1839
                                'stack_%s' % (name), 'basic-style-1arg')
52b0e32 by Walter Bender at 2012-06-16 1840
1841
    def _update_box_names(self, name):
2fee6e6 by Walter Bender at 2012-06-23 1842
        ''' change the label on box blocks of the same name '''
530ac92 by Walter Bender at 2013-05-05 1843
        if isinstance(name, (float, int)):
585cac9 by Walter Bender at 2012-07-18 1844
            return
530ac92 by Walter Bender at 2013-05-05 1845
        if isinstance(name, unicode):
d9d5552 by Walter Bender at 2012-07-19 1846
            name = name.encode('ascii', 'replace')
52b0e32 by Walter Bender at 2012-06-16 1847
        for blk in self.just_blocks():
1848
            if self._box_name(blk, storein=False):
1849
                if blk.spr.labels[0] == self._saved_box_name:
1850
                    blk.spr.labels[0] = name
1851
                    blk.values[0] = name
db6f971 by Walter Bender at 2013-01-25 1852
                if blk.status == 'collapsed':
1853
                    blk.spr.hide()
ca5dc29 by Walter Bender at 2013-01-25 1854
                else:
1855
                    blk.spr.set_layer(BLOCK_LAYER)
144d719 by Walter Bender at 2012-06-23 1856
        self._update_proto_name(name, 'box_%s' % (self._saved_box_name),
cdc5a20 by Walter Bender at 2012-06-16 1857
                                'box_%s' % (name), 'number-style-1strarg')
52b0e32 by Walter Bender at 2012-06-16 1858
223c3f8 by Walter Bender at 2012-07-25 1859
    def _update_storein_names(self, name):
1860
        ''' change the label on storin blocks of the same name '''
530ac92 by Walter Bender at 2013-05-05 1861
        if isinstance(name, (float, int)):
223c3f8 by Walter Bender at 2012-07-25 1862
            return
530ac92 by Walter Bender at 2013-05-05 1863
        if isinstance(name, unicode):
223c3f8 by Walter Bender at 2012-07-25 1864
            name = name.encode('ascii', 'replace')
1865
        for blk in self.just_blocks():
1866
            if self._box_name(blk, storein=True):
1867
                if blk.spr.labels[0] == self._saved_box_name:
1868
                    blk.spr.labels[0] = name
1869
                    blk.values[0] = name
db6f971 by Walter Bender at 2013-01-25 1870
                if blk.status == 'collapsed':
1871
                    blk.spr.hide()
ca5dc29 by Walter Bender at 2013-01-25 1872
                else:
1873
                    blk.spr.set_layer(BLOCK_LAYER)
223c3f8 by Walter Bender at 2012-07-25 1874
        self._update_proto_name(name, 'storein_%s' % (self._saved_box_name),
1875
                                'storein_%s' % (name), 'basic-style-2arg',
1876
                                label=1)
1877
1878
    def _update_proto_name(self, name, old, new, style, palette='blocks',
1879
                           label=0):
144d719 by Walter Bender at 2012-06-23 1880
        ''' Change the name of a proto block '''
1881
        # The name change has to happen in multiple places:
1882
        # (1) The proto block itself
1883
        # (2) The list of block styles
1884
        # (3) The list of proto blocks on the palette
1885
        # (4) The list of block names
530ac92 by Walter Bender at 2013-05-05 1886
        if isinstance(name, unicode):
d9d5552 by Walter Bender at 2012-07-19 1887
            name = name.encode('ascii', 'replace')
530ac92 by Walter Bender at 2013-05-05 1888
        if isinstance(old, unicode):
d9d5552 by Walter Bender at 2012-07-19 1889
            old = old.encode('ascii', 'replace')
530ac92 by Walter Bender at 2013-05-05 1890
        if isinstance(new, unicode):
d9d5552 by Walter Bender at 2012-07-19 1891
            new = new.encode('ascii', 'replace')
1892
144d719 by Walter Bender at 2012-06-23 1893
        if old == new:
223c3f8 by Walter Bender at 2012-07-25 1894
            '''
9d88c67 by Walter Bender at 2012-07-02 1895
            debug_output('update_proto_name: %s == %s' % (old, new),
1896
                         self.running_sugar)
223c3f8 by Walter Bender at 2012-07-25 1897
            '''
144d719 by Walter Bender at 2012-06-23 1898
            return
1899
d9d5552 by Walter Bender at 2012-07-19 1900
        if old in block_styles[style]:
1901
            block_styles[style].remove(old)
1902
        if not new in block_styles[style]:
1903
            block_styles[style].append(new)
1904
1905
        if old in block_names:
1906
            del block_names[old]
1907
        if not new in block_names:
1908
            block_names[new] = name
1909
144d719 by Walter Bender at 2012-06-23 1910
        i = palette_name_to_index(palette)
d9d5552 by Walter Bender at 2012-07-19 1911
        for blk in self.palettes[i]:
52b0e32 by Walter Bender at 2012-06-16 1912
            if blk.name == old:
1913
                blk.name = new
223c3f8 by Walter Bender at 2012-07-25 1914
                blk.spr.labels[label] = name
52b0e32 by Walter Bender at 2012-06-16 1915
                blk.spr.set_layer(PROTO_LAYER)
cdc5a20 by Walter Bender at 2012-06-16 1916
                blk.resize()
144d719 by Walter Bender at 2012-06-23 1917
                break  # Should only be one proto block by this name
1918
1919
        if old in palette_blocks[i]:
1920
            palette_blocks[i].remove(old)
1921
        if not new in palette_blocks[i]:
1922
            palette_blocks[i].append(new)
1923
1924
        self.show_toolbar_palette(i, regenerate=True)
52b0e32 by Walter Bender at 2012-06-16 1925
1926
    def _action_name(self, blk, hat=False):
2fee6e6 by Walter Bender at 2012-06-23 1927
        ''' is this a label for an action block? '''
52b0e32 by Walter Bender at 2012-06-16 1928
        if blk is None:
1929
            return False
585cac9 by Walter Bender at 2012-07-18 1930
        if blk.name != 'string':  # Ignoring int/float names
52b0e32 by Walter Bender at 2012-06-16 1931
            return False
9d88c67 by Walter Bender at 2012-07-02 1932
        if blk.connections is None:
1933
            return False
52b0e32 by Walter Bender at 2012-06-16 1934
        if blk.connections[0] is None:
1935
            return False
1936
        if hat and blk.connections[0].name == 'hat':
1937
            return True
1938
        if not hat and blk.connections[0].name == 'stack':
1939
            return True
1940
        return False
1941
1942
    def _box_name(self, blk, storein=False):
2fee6e6 by Walter Bender at 2012-06-23 1943
        ''' is this a label for a storein block? '''
52b0e32 by Walter Bender at 2012-06-16 1944
        if blk is None:
1945
            return False
1946
        if blk.name != 'string':  # Ignoring int names
1947
            return False
9d88c67 by Walter Bender at 2012-07-02 1948
        if blk.connections is None:
1949
            return False
52b0e32 by Walter Bender at 2012-06-16 1950
        if blk.connections[0] is None:
1951
            return False
1952
        if storein and blk.connections[0].name == 'storein':
5bc53fb by Walter Bender at 2012-09-01 1953
            if blk.connections[0].connections[1] == blk:
1954
                return True
1955
            else:
1956
                return False
52b0e32 by Walter Bender at 2012-06-16 1957
        if not storein and blk.connections[0].name == 'box':
1958
            return True
1959
        return False
1960
c2937d9 by Walter Bender at 2010-08-12 1961
    def _select_category(self, spr):
2fee6e6 by Walter Bender at 2012-06-23 1962
        ''' Select a category from the toolbar '''
c2937d9 by Walter Bender at 2010-08-12 1963
        i = self.selectors.index(spr)
1964
        spr.set_shape(self.selector_shapes[i][1])
1965
        if self.selected_selector is not None:
1966
            j = self.selectors.index(self.selected_selector)
1967
            if i == j:
1968
                return
1969
            self.selected_selector.set_shape(self.selector_shapes[j][0])
1970
        self.previous_selector = self.selected_selector
1971
        self.selected_selector = spr
1972
        self.show_palette(i)
1973
1974
    def _select_toolbar_button(self, spr):
2fee6e6 by Walter Bender at 2012-06-23 1975
        ''' Select a toolbar button (Used when not running Sugar). '''
c2937d9 by Walter Bender at 2010-08-12 1976
        if not hasattr(spr, 'name'):
1977
            return
1978
        if spr.name == 'run-fastoff':
1979
            self.lc.trace = 0
ef8850f by Walter Bender at 2012-05-03 1980
            self.hideblocks()
a01b019 by Walter Bender at 2012-05-12 1981
            self.display_coordinates(clear=True)
c2937d9 by Walter Bender at 2010-08-12 1982
            self.run_button(0)
1983
        elif spr.name == 'run-slowoff':
dc545b2 by Walter Bender at 2011-03-03 1984
            self.lc.trace = 1
a01b019 by Walter Bender at 2012-05-12 1985
            self.showblocks()
c2937d9 by Walter Bender at 2010-08-12 1986
            self.run_button(3)
1987
        elif spr.name == 'stopiton':
1988
            self.stop_button()
a01b019 by Walter Bender at 2012-05-12 1989
            self.display_coordinates()
1990
            self.showblocks()
c2937d9 by Walter Bender at 2010-08-12 1991
            self.toolbar_shapes['stopiton'].hide()
1992
        elif spr.name == 'eraseron':
1993
            self.eraser_button()
1994
        elif spr.name == 'hideshowoff':
1995
            self.hideshow_button()
1996
1997
    def _put_in_trash(self, blk, x=0, y=0):
2fee6e6 by Walter Bender at 2012-06-23 1998
        ''' Put a group of blocks into the trash. '''
c2937d9 by Walter Bender at 2010-08-12 1999
        self.trash_stack.append(blk)
2000
        group = find_group(blk)
2001
        for gblk in group:
2002
            gblk.type = 'trash'
2003
            gblk.rescale(self.trash_scale)
2004
        blk.spr.move((x, y))
2005
        for gblk in group:
2006
            self._adjust_dock_positions(gblk)
2007
2008
        # And resize any skins.
2009
        for gblk in group:
2010
            if gblk.name in BLOCKS_WITH_SKIN:
2011
                self._resize_skin(gblk)
dcd7408 by Walter Bender at 2010-10-10 2012
98ed32f by Walter Bender at 2013-06-03 2013
        if not 'trash' in palette_names or \
2014
                self.selected_palette != palette_names.index('trash'):
c2937d9 by Walter Bender at 2010-08-12 2015
            for gblk in group:
2016
                gblk.spr.hide()
2017
144d719 by Walter Bender at 2012-06-23 2018
        # If there was a named hat or storein, remove it from the
2019
        # proto palette, the palette name list, the block name list,
2020
        # and the style list
52b0e32 by Walter Bender at 2012-06-16 2021
        for gblk in group:
144d719 by Walter Bender at 2012-06-23 2022
            if (gblk.name == 'hat' or gblk.name == 'storein') and \
52b0e32 by Walter Bender at 2012-06-16 2023
               gblk.connections is not None and \
2024
               gblk.connections[1] is not None and \
144d719 by Walter Bender at 2012-06-23 2025
               gblk.connections[1].name == 'string':
2026
                if gblk.name == 'hat':
223c3f8 by Walter Bender at 2012-07-25 2027
                    self._remove_palette_blocks(
4fff361 by Walter Bender at 2013-05-22 2028
                        'stack_%s' % (gblk.connections[1].values[0]),
223c3f8 by Walter Bender at 2012-07-25 2029
                        'basic-style-1arg')
4fff361 by Walter Bender at 2013-05-22 2030
                else:  # Only if it was the only one
223c3f8 by Walter Bender at 2012-07-25 2031
                    remove = True
2032
                    similars = self.block_list.get_similar_blocks(
2033
                        'block', 'storein')
2034
                    for blk in similars:
2035
                        if blk.connections is not None and \
2036
                           blk.connections[1] is not None and \
2037
                           blk.connections[1].name == 'string':
2038
                            if blk.connections[1].values[0] == \
2039
                               gblk.connections[1].values[0]:
2040
                                remove = False
2041
                    similars = self.block_list.get_similar_blocks(
2042
                        'block', 'box')
2043
                    for blk in similars:
2044
                        if blk.connections is not None and \
2045
                           blk.connections[1] is not None and \
2046
                           blk.connections[1].name == 'string':
2047
                            if blk.connections[1].values[0] == \
2048
                               gblk.connections[1].values[0]:
2049
                                remove = False
2050
                    if remove:
2051
                        self._remove_palette_blocks(
2052
                            'box_%s' % gblk.connections[1].values[0],
2053
                            'number-style-1strarg')
2054
                        self._remove_palette_blocks(
2055
                            'storein_%s' % gblk.connections[1].values[0],
2056
                            'basic-style-2arg')
2057
2058
    def _remove_palette_blocks(self, name, style, palette='blocks'):
2059
        ''' Remove blocks from palette and block, style lists '''
2060
        i = palette_name_to_index('blocks')
2061
        if name in palette_blocks[i]:
2062
            palette_blocks[i].remove(name)
2063
            for blk in self.palettes[i]:
2064
                if blk.name == name:
2065
                    blk.spr.hide()
2066
                    self.palettes[i].remove(blk)
2067
            self.show_toolbar_palette(i, regenerate=True)
2068
        if name in block_styles[style]:
2069
            block_styles[style].remove(name)
2070
        if name in block_names:
2071
            del block_names[name]
52b0e32 by Walter Bender at 2012-06-16 2072
c2937d9 by Walter Bender at 2010-08-12 2073
    def _restore_all_from_trash(self):
2fee6e6 by Walter Bender at 2012-06-23 2074
        ''' Restore all the blocks in the trash can. '''
c2937d9 by Walter Bender at 2010-08-12 2075
        for blk in self.block_list.list:
2076
            if blk.type == 'trash':
2077
                self._restore_from_trash(blk)
2078
28be071 by Walter Bender at 2012-07-31 2079
    def restore_latest_from_trash(self):
2fee6e6 by Walter Bender at 2012-06-23 2080
        ''' Restore most recent blocks from the trash can. '''
c2937d9 by Walter Bender at 2010-08-12 2081
        if len(self.trash_stack) == 0:
2082
            return
2083
        self._restore_from_trash(self.trash_stack[len(self.trash_stack) - 1])
2084
2085
    def _restore_from_trash(self, blk):
2086
        group = find_group(blk)
505d953 by Walter Bender at 2012-07-06 2087
2088
        for gblk in group:
2089
            if gblk.name == 'sandwichclampcollapsed':
2090
                restore_clamp(gblk)
2091
                self.resize_parent_clamps(gblk)
2092
c2937d9 by Walter Bender at 2010-08-12 2093
        for gblk in group:
2094
            gblk.rescale(self.block_scale)
2095
            gblk.spr.set_layer(BLOCK_LAYER)
2096
            x, y = gblk.spr.get_xy()
2097
            if self.orientation == 0:
2098
                gblk.spr.move((x, y + PALETTE_HEIGHT + self.toolbar_offset))
2099
            else:
2100
                gblk.spr.move((x + PALETTE_WIDTH, y))
2101
            gblk.type = 'block'
505d953 by Walter Bender at 2012-07-06 2102
c2937d9 by Walter Bender at 2010-08-12 2103
        for gblk in group:
2104
            self._adjust_dock_positions(gblk)
ae39e44 by Walter Bender at 2011-11-03 2105
c2937d9 by Walter Bender at 2010-08-12 2106
        # And resize any skins.
2107
        for gblk in group:
2108
            if gblk.name in BLOCKS_WITH_SKIN:
2109
                self._resize_skin(gblk)
2110
2111
        self.trash_stack.remove(blk)
2112
2113
    def _empty_trash(self):
2fee6e6 by Walter Bender at 2012-06-23 2114
        ''' Permanently remove all blocks presently in the trash can. '''
c2937d9 by Walter Bender at 2010-08-12 2115
        for blk in self.block_list.list:
2116
            if blk.type == 'trash':
2117
                blk.type = 'deleted'
2118
                blk.spr.hide()
2119
        self.trash_stack = []
4fff361 by Walter Bender at 2013-05-22 2120
        self.show_toolbar_palette(palette_names.index('trash'),
2121
                                  regenerate=True)
c2937d9 by Walter Bender at 2010-08-12 2122
2123
    def _in_the_trash(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 2124
        ''' Is x, y over a palette? '''
dcd7408 by Walter Bender at 2010-10-10 2125
        if self.selected_palette is not None and \
4fff361 by Walter Bender at 2013-05-22 2126
                self.palette_sprs[self.selected_palette][self.orientation]\
2127
                .hit((x, y)):
c2937d9 by Walter Bender at 2010-08-12 2128
            return True
2129
        return False
2130
2131
    def _block_pressed(self, x, y, blk):
2fee6e6 by Walter Bender at 2012-06-23 2132
        ''' Block pressed '''
c2937d9 by Walter Bender at 2010-08-12 2133
        if blk is not None:
2134
            blk.highlight()
2135
            self._disconnect(blk)
2136
            self.drag_group = find_group(blk)
2137
            (sx, sy) = blk.spr.get_xy()
dcd7408 by Walter Bender at 2010-10-10 2138
            self.drag_pos = x - sx, y - sy
7f1f1c9 by Walter Bender at 2012-07-02 2139
            for blk in self.drag_group:
2140
                if blk.status != 'collapsed':
2141
                    blk.spr.set_layer(TOP_LAYER)
6553d94 by Walter Bender at 2013-05-08 2142
            if self.copying_blocks or self.sharing_blocks or \
2143
               self.saving_blocks:
f2ea57b by Walter Bender at 2013-05-06 2144
                for blk in self.drag_group:
2145
                    if blk.status != 'collapsed':
2146
                        blk.highlight()
2147
                self.block_operation = 'copying'
2148
                data = self.assemble_data_to_save(False, False)
2149
6553d94 by Walter Bender at 2013-05-08 2150
                if data is not []:
2151
                    if self.saving_blocks:
2152
                        debug_output('Serialize blocks and save.',
2153
                                     self.running_sugar)
2154
                        i = find_hat(data)
2467422 by Walter Bender at 2013-05-09 2155
                        if i is not None:
2156
                            name = ''
6553d94 by Walter Bender at 2013-05-08 2157
                            try:
2158
                                name = str(data[data[i][4][1]][1][1])
2159
                            except:
2467422 by Walter Bender at 2013-05-09 2160
                                pass
2161
                            if name == '':
2162
                                name = 'stack_%d' % (int(uniform(0, 10000)))
6553d94 by Walter Bender at 2013-05-08 2163
                            debug_output('saving macro %s' % (name),
2164
                                         self.running_sugar)
2165
                            if not os.path.exists(self.macros_path):
2166
                                try:
2167
                                    os.makedirs(self.macros_path)
2168
                                except OSError, exc:
2169
                                    if exc.errno == errno.EEXIST:
2170
                                        pass
2171
                                    else:
2172
                                        raise
2467422 by Walter Bender at 2013-05-09 2173
                            macro_path = os.path.join(
2174
                                self.macros_path, '%s.tb' % (name))
2175
                            # Make sure name is unique
1442d65 by Walter Bender at 2013-05-09 2176
                            if os.path.exists(macro_path):
2177
                                self._save_stack_alert(name, data, macro_path)
2178
                            else:
2179
                                self._save_stack(data, macro_path)
2180
                            self.drag_group = None
6553d94 by Walter Bender at 2013-05-08 2181
                    elif self.copying_blocks:
2182
                        clipboard = gtk.Clipboard()
2183
                        debug_output('Serialize blocks and copy to clipboard',
2184
                                     self.running_sugar)
2185
                        text = data_to_string(data)
2186
                        clipboard.set_text(text)
2187
                    elif self.sharing():
2188
                        debug_output('Serialize blocks and send as event',
2189
                                     self.running_sugar)
2190
                        text = data_to_string(data)
2191
                        event = 'B|%s' % (data_to_string([self.nick, text]))
2192
                        self.send_event(event)
2193
            self.paste_offset = 20
2194
2195
            self.parent.get_window().set_cursor(
2196
                gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
2197
            self.saving_blocks = False
2198
64384f5 by Walter Bender at 2012-06-13 2199
            if self.running_sugar and self._sharing and \
2200
               hasattr(self.activity, 'share_button'):
2201
                self.activity.share_button.set_tooltip(
2202
                    _('Share selected blocks'))
6553d94 by Walter Bender at 2013-05-08 2203
5beecd4 by Walter Bender at 2011-11-12 2204
            if len(blk.spr.labels) > 0:
e8f85f0 by Walter Bender at 2012-10-24 2205
                self._saved_string = blk.spr.labels[0]
2206
                self._saved_action_name = self._saved_string
2207
                self._saved_box_name = self._saved_string
5beecd4 by Walter Bender at 2011-11-12 2208
            else:
e8f85f0 by Walter Bender at 2012-10-24 2209
                self._saved_string = ''
c2937d9 by Walter Bender at 2010-08-12 2210
2211
    def _unselect_block(self):
2fee6e6 by Walter Bender at 2012-06-23 2212
        ''' Unselect block '''
c2937d9 by Walter Bender at 2010-08-12 2213
        # After unselecting a 'number' block, we need to check its value
357da6f by Walter Bender at 2012-11-11 2214
        if self.selected_blk is None:
2215
            return
c2937d9 by Walter Bender at 2010-08-12 2216
        if self.selected_blk.name == 'number':
e8f85f0 by Walter Bender at 2012-10-24 2217
            if self._text_to_check:
2218
                self._test_number()
c2937d9 by Walter Bender at 2010-08-12 2219
        elif self.selected_blk.name == 'string':
e8f85f0 by Walter Bender at 2012-10-24 2220
            if self._text_to_check:
2221
                self._test_string()
2222
        self._text_to_check = False
bb24b95 by Walter Bender at 2012-11-14 2223
        if self._action_name(self.selected_blk, hat=True):
2224
            if self._saved_action_name == _('action'):
2225
                self._new_stack_block(self.selected_blk.spr.labels[0])
2226
            self._update_action_names(self.selected_blk.spr.labels[0])
2227
        elif self._box_name(self.selected_blk, storein=True):
2228
            if self._saved_box_name == _('my box'):
2229
                self._new_storein_block(self.selected_blk.spr.labels[0])
2230
                self._new_box_block(self.selected_blk.spr.labels[0])
2231
            self._update_storein_names(self.selected_blk.spr.labels[0])
2232
            self._update_box_names(self.selected_blk.spr.labels[0])
c2937d9 by Walter Bender at 2010-08-12 2233
        self.selected_blk.unhighlight()
2234
        self.selected_blk = None
2235
f29c61f by Walter Bender at 2011-02-27 2236
    def _new_block(self, name, x, y, defaults=None):
2fee6e6 by Walter Bender at 2012-06-23 2237
        ''' Make a new block. '''
05f2c19 by Raul Gutierrez Segales at 2011-02-27 2238
        x_pos = x - 20
2239
        y_pos = y - 20
a9fb111 by Walter Bender at 2011-03-05 2240
        if name in content_blocks:
4fff361 by Walter Bender at 2013-05-22 2241
            if defaults is None:
a9fb111 by Walter Bender at 2011-03-05 2242
                defaults = default_values[name]
05f2c19 by Raul Gutierrez Segales at 2011-02-27 2243
            newblk = Block(self.block_list, self.sprite_list, name, x_pos,
2244
                           y_pos, 'block', defaults, self.block_scale)
c2937d9 by Walter Bender at 2010-08-12 2245
        else:
05f2c19 by Raul Gutierrez Segales at 2011-02-27 2246
            newblk = Block(self.block_list, self.sprite_list, name, x_pos,
2247
                           y_pos, 'block', [], self.block_scale)
c2937d9 by Walter Bender at 2010-08-12 2248
2249
        # Add a 'skin' to some blocks
2250
        if name in PYTHON_SKIN:
2251
            if self.nop == 'pythonloaded':
2252
                self._block_skin('pythonon', newblk)
2253
            else:
2254
                self._block_skin('pythonoff', newblk)
a9fb111 by Walter Bender at 2011-03-05 2255
        elif name in block_styles['box-style-media']:
ae5a95c by Walter Bender at 2011-07-28 2256
            if name in EXPAND_SKIN:
2257
                if newblk.ex == 0:
ad8aaf0 by Walter Bender at 2011-07-30 2258
                    newblk.expand_in_x(EXPAND_SKIN[name][0])
2259
                if newblk.ey == 0:
2260
                    newblk.expand_in_y(EXPAND_SKIN[name][1])
dcd7408 by Walter Bender at 2010-10-10 2261
            self._block_skin(name + 'off', newblk)
c2937d9 by Walter Bender at 2010-08-12 2262
2263
        newspr = newblk.spr
2264
        newspr.set_layer(TOP_LAYER)
2265
        self.drag_pos = 20, 20
dcd7408 by Walter Bender at 2010-10-10 2266
        newblk.connections = [None] * len(newblk.docks)
a9fb111 by Walter Bender at 2011-03-05 2267
        if newblk.name in default_values:
4fff361 by Walter Bender at 2013-05-22 2268
            if defaults is None:
a9fb111 by Walter Bender at 2011-03-05 2269
                defaults = default_values[newblk.name]
f29c61f by Walter Bender at 2011-02-27 2270
            for i, argvalue in enumerate(defaults):
c2937d9 by Walter Bender at 2010-08-12 2271
                # skip the first dock position since it is always a connector
2272
                dock = newblk.docks[i + 1]
2273
                argname = dock[0]
2274
                if argname == 'unavailable':
2275
                    continue
2276
                if argname == 'media':
2277
                    argname = 'journal'
2278
                elif argname == 'number' and \
4fff361 by Walter Bender at 2013-05-22 2279
                        isinstance(argvalue, (str, unicode)):
c2937d9 by Walter Bender at 2010-08-12 2280
                    argname = 'string'
5d393df by Walter Bender at 2012-12-05 2281
                elif argname == 'string' and \
4fff361 by Walter Bender at 2013-05-22 2282
                        name in block_styles['number-style-1strarg'] and \
2283
                        isinstance(argvalue, (float, int)):
5d393df by Walter Bender at 2012-12-05 2284
                    argname = 'number'
c2937d9 by Walter Bender at 2010-08-12 2285
                elif argname == 'bool':
2286
                    argname = argvalue
2287
                elif argname == 'flow':
2288
                    argname = argvalue
2289
                (sx, sy) = newspr.get_xy()
2290
                if argname is not None:
a9fb111 by Walter Bender at 2011-03-05 2291
                    if argname in content_blocks:
c2937d9 by Walter Bender at 2010-08-12 2292
                        argblk = Block(self.block_list, self.sprite_list,
2293
                                       argname, 0, 0, 'block', [argvalue],
2294
                                       self.block_scale)
2295
                    else:
2296
                        argblk = Block(self.block_list, self.sprite_list,
2297
                                       argname, 0, 0, 'block', [],
2298
                                       self.block_scale)
2299
                    argdock = argblk.docks[0]
2300
                    nx = sx + dock[2] - argdock[2]
2301
                    ny = sy + dock[3] - argdock[3]
2302
                    if argname == 'journal':
2303
                        self._block_skin('journaloff', argblk)
2304
                    argblk.spr.move((nx, ny))
2305
                    argblk.spr.set_layer(TOP_LAYER)
2306
                    argblk.connections = [newblk, None]
2307
                    newblk.connections[i + 1] = argblk
2308
        self.drag_group = find_group(newblk)
dcd7408 by Walter Bender at 2010-10-10 2309
        self.block_operation = 'new'
1b4590d by Walter Bender at 2011-11-11 2310
        if len(newblk.spr.labels) > 0 and newblk.spr.labels[0] is not None \
2311
                and newblk.name not in ['', 'number', 'string']:
a10bc4f by Walter Bender at 2012-01-18 2312
            if len(self.used_block_list) > 0:
2313
                self.used_block_list.append(', ')
2314
            if newblk.name in special_names:
2315
                self.used_block_list.append(special_names[newblk.name])
2316
            elif newblk.spr.labels[0] not in self.used_block_list:
f6b39fb by Walter Bender at 2011-10-22 2317
                self.used_block_list.append(newblk.spr.labels[0])
c2937d9 by Walter Bender at 2010-08-12 2318
bafc3af by Walter Bender at 2012-07-21 2319
    def new_macro(self, name, x, y):
0ee623d by Walter Bender at 2013-07-23 2320
        ''' Create a 'macro' (predefined stack of blocks). '''
c2937d9 by Walter Bender at 2010-08-12 2321
        macro = MACROS[name]
2322
        macro[0][2] = x
2323
        macro[0][3] = y
2324
        top = self.process_data(macro)
dcd7408 by Walter Bender at 2010-10-10 2325
        self.block_operation = 'new'
c2937d9 by Walter Bender at 2010-08-12 2326
        self.drag_group = find_group(top)
2327
2328
    def process_data(self, block_data, offset=0):
2fee6e6 by Walter Bender at 2012-06-23 2329
        ''' Process block_data (from a macro, a file, or the clipboard). '''
9d88c67 by Walter Bender at 2012-07-02 2330
        self._process_block_data = []
2331
        for blk in block_data:
2332
            if not self._found_a_turtle(blk):
2333
                self._process_block_data.append(
2334
                    [blk[0], blk[1], blk[2], blk[3], blk[4]])
2335
        self._extra_block_data = []
c2937d9 by Walter Bender at 2010-08-12 2336
        # Create the blocks (or turtle).
2337
        blocks = []
b0a9e84 by Walter Bender at 2012-12-08 2338
        for i, blk in enumerate(self._process_block_data):
c2937d9 by Walter Bender at 2010-08-12 2339
            if not self._found_a_turtle(blk):
ea90a80 by Walter Bender at 2012-07-06 2340
                newblk = self.load_block(blk, offset)
2341
                if newblk is not None:
2342
                    blocks.append(newblk)
6bcc4e9 by Walter Bender at 2013-01-16 2343
                    if newblk.spr is not None:
2344
                        newblk.spr.set_layer(TOP_LAYER)
b0a9e84 by Walter Bender at 2012-12-08 2345
                else:
2346
                    blocks.append(None)
9d88c67 by Walter Bender at 2012-07-02 2347
        # Some extra blocks may have been added by load_block
2348
        for blk in self._extra_block_data:
2349
            self._process_block_data.append(blk)
ea90a80 by Walter Bender at 2012-07-06 2350
            newblk = self.load_block(blk, offset)
2351
            if newblk is not None:
2352
                blocks.append(newblk)
6bcc4e9 by Walter Bender at 2013-01-16 2353
                if newblk.spr is not None:
2354
                    newblk.spr.set_layer(TOP_LAYER)
c2937d9 by Walter Bender at 2010-08-12 2355
2356
        # Make the connections.
b0a9e84 by Walter Bender at 2012-12-08 2357
        for i, blk in enumerate(blocks):
2358
            if blk is None:
2359
                continue
c2937d9 by Walter Bender at 2010-08-12 2360
            cons = []
2361
            # Normally, it is simply a matter of copying the connections.
b0a9e84 by Walter Bender at 2012-12-08 2362
            if blk.connections is None:
9d88c67 by Walter Bender at 2012-07-02 2363
                if self._process_block_data[i][4] is not None:
2364
                    for c in self._process_block_data[i][4]:
ddd48d3 by Walter Bender at 2010-10-15 2365
                        if c is None or c > (len(blocks) - 1):
2366
                            cons.append(None)
2367
                        else:
2368
                            cons.append(blocks[c])
2369
                else:
0ee623d by Walter Bender at 2013-07-23 2370
                    debug_output('connection error %s' %
4fff361 by Walter Bender at 2013-05-22 2371
                                 (str(self._process_block_data[i])),
7f56a04 by Walter Bender at 2011-02-22 2372
                                 self.running_sugar)
ddd48d3 by Walter Bender at 2010-10-15 2373
                    cons.append(None)
b0a9e84 by Walter Bender at 2012-12-08 2374
            elif blk.connections == 'check':
dcd7408 by Walter Bender at 2010-10-10 2375
                # Convert old-style boolean and arithmetic blocks
a64f47c by Walter Bender at 2010-11-20 2376
                cons.append(None)  # Add an extra connection.
9d88c67 by Walter Bender at 2012-07-02 2377
                for c in self._process_block_data[i][4]:
c2937d9 by Walter Bender at 2010-08-12 2378
                    if c is None:
2379
                        cons.append(None)
2380
                    else:
2381
                        cons.append(blocks[c])
2382
                # If the boolean op was connected, readjust the plumbing.
b0a9e84 by Walter Bender at 2012-12-08 2383
                if blk.name in block_styles['boolean-style']:
9d88c67 by Walter Bender at 2012-07-02 2384
                    if self._process_block_data[i][4][0] is not None:
2385
                        c = self._process_block_data[i][4][0]
2386
                        cons[0] = blocks[self._process_block_data[c][4][0]]
2387
                        c0 = self._process_block_data[c][4][0]
4fff361 by Walter Bender at 2013-05-22 2388
                        for j, cj \
2389
                                in enumerate(self._process_block_data[c0][4]):
c2937d9 by Walter Bender at 2010-08-12 2390
                            if cj == c:
b0a9e84 by Walter Bender at 2012-12-08 2391
                                blocks[c0].connections[j] = blk
c2937d9 by Walter Bender at 2010-08-12 2392
                        if c < i:
b0a9e84 by Walter Bender at 2012-12-08 2393
                            blocks[c].connections[0] = blk
c2937d9 by Walter Bender at 2010-08-12 2394
                            blocks[c].connections[3] = None
2395
                        else:
2396
                            # Connection was to a block we haven't seen yet.
0ee623d by Walter Bender at 2013-07-23 2397
                            debug_output('Warning: dock to the future',
7f56a04 by Walter Bender at 2011-02-22 2398
                                         self.running_sugar)
c2937d9 by Walter Bender at 2010-08-12 2399
                else:
9d88c67 by Walter Bender at 2012-07-02 2400
                    if self._process_block_data[i][4][0] is not None:
2401
                        c = self._process_block_data[i][4][0]
2402
                        cons[0] = blocks[self._process_block_data[c][4][0]]
2403
                        c0 = self._process_block_data[c][4][0]
4fff361 by Walter Bender at 2013-05-22 2404
                        for j, cj \
2405
                                in enumerate(self._process_block_data[c0][4]):
c2937d9 by Walter Bender at 2010-08-12 2406
                            if cj == c:
b0a9e84 by Walter Bender at 2012-12-08 2407
                                blocks[c0].connections[j] = blk
c2937d9 by Walter Bender at 2010-08-12 2408
                        if c < i:
b0a9e84 by Walter Bender at 2012-12-08 2409
                            blocks[c].connections[0] = blk
c2937d9 by Walter Bender at 2010-08-12 2410
                            blocks[c].connections[1] = None
2411
                        else:
2412
                            # Connection was to a block we haven't seen yet.
0ee623d by Walter Bender at 2013-07-23 2413
                            debug_output('Warning: dock to the future',
7f56a04 by Walter Bender at 2011-02-22 2414
                                         self.running_sugar)
c2937d9 by Walter Bender at 2010-08-12 2415
            else:
0ee623d by Walter Bender at 2013-07-23 2416
                debug_output('Warning: unknown connection state %s' %
4fff361 by Walter Bender at 2013-05-22 2417
                             (str(blk.connections)), self.running_sugar)
b0a9e84 by Walter Bender at 2012-12-08 2418
            blk.connections = cons[:]
c2937d9 by Walter Bender at 2010-08-12 2419
2420
        # Block sizes and shapes may have changed.
2421
        for blk in blocks:
b0a9e84 by Walter Bender at 2012-12-08 2422
            if blk is None:
2423
                continue
c2937d9 by Walter Bender at 2010-08-12 2424
            self._adjust_dock_positions(blk)
2425
505d953 by Walter Bender at 2012-07-06 2426
        # Look for any stacks that need to be collapsed
c2937d9 by Walter Bender at 2010-08-12 2427
        for blk in blocks:
b0a9e84 by Walter Bender at 2012-12-08 2428
            if blk is None:
2429
                continue
6c56adb by Walter Bender at 2012-07-05 2430
            if blk.name == 'sandwichclampcollapsed':
2431
                collapse_clamp(blk, False)
2432
0be98e5 by Walter Bender at 2012-07-05 2433
        # process in reverse order
2434
        for i in range(len(blocks)):
2435
            blk = blocks[-i - 1]
b0a9e84 by Walter Bender at 2012-12-08 2436
            if blk is None:
2437
                continue
0be98e5 by Walter Bender at 2012-07-05 2438
            if blk.name in EXPANDABLE_FLOW:
2439
                if blk.name in block_styles['clamp-style-1arg'] or\
2440
                   blk.name in block_styles['clamp-style-boolean']:
2441
                    if blk.connections[2] is not None:
2442
                        self._resize_clamp(blk, blk.connections[2])
2443
                elif blk.name in block_styles['clamp-style']:
2444
                    if blk.connections[1] is not None:
2445
                        self._resize_clamp(blk, blk.connections[1])
2446
                elif blk.name in block_styles['clamp-style-else']:
2447
                    if blk.connections[2] is not None:
2448
                        self._resize_clamp(blk, blk.connections[2], dockn=2)
2449
                    if blk.connections[3] is not None:
2450
                        self._resize_clamp(blk, blk.connections[3], dockn=3)
2451
b0a9e84 by Walter Bender at 2012-12-08 2452
        # Eliminate None blocks from the block list
2453
        blocks_copy = []
2454
        for blk in blocks:
2455
            if blk is not None:
2456
                blocks_copy.append(blk)
2457
        blocks = blocks_copy[:]
2458
c2937d9 by Walter Bender at 2010-08-12 2459
        # Resize blocks to current scale
6bcc4e9 by Walter Bender at 2013-01-16 2460
        if self.interactive_mode:
2461
            self.resize_blocks(blocks)
c2937d9 by Walter Bender at 2010-08-12 2462
2463
        if len(blocks) > 0:
2464
            return blocks[0]
2465
        else:
2466
            return None
2467
2468
    def _adjust_dock_positions(self, blk):
2fee6e6 by Walter Bender at 2012-06-23 2469
        ''' Adjust the dock x, y positions '''
c2937d9 by Walter Bender at 2010-08-12 2470
        if not self.interactive_mode:
2471
            return
2472
        (sx, sy) = blk.spr.get_xy()
2473
        for i, c in enumerate(blk.connections):
59fbd43 by Walter Bender at 2011-03-24 2474
            if i > 0 and c is not None and i < len(blk.docks):
c2937d9 by Walter Bender at 2010-08-12 2475
                bdock = blk.docks[i]
2476
                for j in range(len(c.docks)):
ddd48d3 by Walter Bender at 2010-10-15 2477
                    if j < len(c.connections) and c.connections[j] == blk:
c2937d9 by Walter Bender at 2010-08-12 2478
                        cdock = c.docks[j]
dcd7408 by Walter Bender at 2010-10-10 2479
                        nx = sx + bdock[2] - cdock[2]
c2937d9 by Walter Bender at 2010-08-12 2480
                        ny = sy + bdock[3] - cdock[3]
2481
                        c.spr.move((nx, ny))
2482
                self._adjust_dock_positions(c)
2483
2484
    def _turtle_pressed(self, x, y):
0dda146 by Walter Bender at 2013-06-25 2485
        pos = self.selected_turtle.get_xy()
2486
        tpos = self.turtles.turtle_to_screen_coordinates(pos)
2487
        dx = x - tpos[0]
2488
        dy = y - tpos[1]
d141424 by Walter Bender at 2010-10-25 2489
        if not hasattr(self.lc, 'value_blocks'):
2490
            self.lc.find_value_blocks()
2491
        self.lc.update_values = True
0dda146 by Walter Bender at 2013-06-25 2492
        # Compare distance squared of drag position to sprite radius.
2493
        # If x, y is near the edge, rotate.
b5e3e3a by Walter Bender at 2013-06-26 2494
        if (dx * dx) + (dy * dy) > self.selected_turtle.get_drag_radius():
0dda146 by Walter Bender at 2013-06-25 2495
            self.drag_turtle = (
2496
                'turn',
2497
                self.selected_turtle.get_heading() - atan2(dy, dx) / DEGTOR,
2498
                0)
c2937d9 by Walter Bender at 2010-08-12 2499
        else:
0dda146 by Walter Bender at 2013-06-25 2500
            self.drag_turtle = ('move', x - tpos[0], y - tpos[1])
c2937d9 by Walter Bender at 2010-08-12 2501
2502
    def _move_cb(self, win, event):
2503
        x, y = xy(event)
f968c54 by Walter Bender at 2011-11-17 2504
        self.mouse_x = x
2505
        self.mouse_y = y
c2937d9 by Walter Bender at 2010-08-12 2506
        self._mouse_move(x, y)
2507
        return True
2508
5ddf280 by Walter Bender at 2011-10-06 2509
    def _share_mouse_move(self):
2510
        ''' Share turtle movement and rotation after button up '''
2511
        if self.sharing():
2512
            nick = self.turtle_movement_to_share.get_name()
0ee623d by Walter Bender at 2013-07-23 2513
            self.send_event('r|%s' % (data_to_string(
2aa89e8 by Walter Bender at 2013-06-26 2514
                [nick,
2515
                 round_int(self.turtles.get_active_turtle().get_heading())])))
4aaa75f by Walter Bender at 2013-06-25 2516
            if self.turtles.get_active_turtle().get_pen_state():
5ddf280 by Walter Bender at 2011-10-06 2517
                self.send_event('p|%s' % (data_to_string([nick, False])))
2518
                put_pen_back_down = True
2519
            else:
2520
                put_pen_back_down = False
0ee623d by Walter Bender at 2013-07-23 2521
            self.send_event('x|%s' % (data_to_string(
2aa89e8 by Walter Bender at 2013-06-26 2522
                [nick,
2523
                 [round_int(self.turtles.get_active_turtle().get_xy()[0]),
2524
                  round_int(self.turtles.get_active_turtle().get_xy()[1])]])))
5ddf280 by Walter Bender at 2011-10-06 2525
            if put_pen_back_down:
2526
                self.send_event('p|%s' % (data_to_string([nick, True])))
2527
        self.turtle_movement_to_share = None
2528
235bcc7 by Walter Bender at 2010-08-18 2529
    def _mouse_move(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 2530
        ''' Process mouse movements '''
60d0d9c by Walter Bender at 2012-04-10 2531
4dfcb24 by Walter Bender at 2012-04-18 2532
        if self.running_sugar and self.dragging_canvas[0]:
2ca3c1f by Walter Bender at 2013-02-22 2533
            # Don't adjust with each mouse move or GTK cannot keep pace.
2534
            if self.dragging_counter < 10:
2535
                self.dragging_dx += self.dragging_canvas[1] - x
2536
                self.dragging_dy += self.dragging_canvas[2] - y
2537
                self.dragging_canvas[1] = x
2538
                self.dragging_canvas[2] = y
2539
                self.dragging_counter += 1
2540
            else:
2541
                self.activity.adjust_sw(self.dragging_dx, self.dragging_dy)
2542
                self.dragging_counter = 0
2543
                self.dragging_dx = 0
2544
                self.dragging_dy = 0
60d0d9c by Walter Bender at 2012-04-10 2545
            return True
2546
c2937d9 by Walter Bender at 2010-08-12 2547
        self.block_operation = 'move'
235bcc7 by Walter Bender at 2010-08-18 2548
c2937d9 by Walter Bender at 2010-08-12 2549
        # First, check to see if we are dragging or rotating a turtle.
2550
        if self.selected_turtle is not None:
0dda146 by Walter Bender at 2013-06-25 2551
            drag_type, dragx, dragy = self.drag_turtle
798b366 by Walter Bender at 2013-03-01 2552
            self.update_counter += 1
0dda146 by Walter Bender at 2013-06-25 2553
            if drag_type == 'move':
2554
                dx = x - dragx
2555
                dy = y - dragy
7b697bd by Walter Bender at 2010-08-21 2556
                self.selected_turtle.spr.set_layer(TOP_LAYER)
0dda146 by Walter Bender at 2013-06-25 2557
                pos = self.turtles.screen_to_turtle_coordinates((dx, dy))
2558
                if self.selected_turtle.get_pen_state():
2559
                    self.selected_turtle.set_pen_state(False)
bc09b50 by Walter Bender at 2013-08-21 2560
                    self.selected_turtle.set_xy(pos, share=False, dragging=True)
0dda146 by Walter Bender at 2013-06-25 2561
                    self.selected_turtle.set_pen_state(True)
18d586f by Walter Bender at 2011-03-13 2562
                else:
bc09b50 by Walter Bender at 2013-08-21 2563
                    self.selected_turtle.set_xy(pos, share=False, dragging=True)
798b366 by Walter Bender at 2013-03-01 2564
                if self.update_counter % 5:
f5a2055 by Walter Bender at 2013-03-01 2565
                    self.lc.update_label_value(
0dda146 by Walter Bender at 2013-06-25 2566
                        'xcor', self.selected_turtle.get_xy()[0] /
2567
                        self.coord_scale)
f5a2055 by Walter Bender at 2013-03-01 2568
                    self.lc.update_label_value(
0dda146 by Walter Bender at 2013-06-25 2569
                        'ycor', self.selected_turtle.get_xy()[1] /
2570
                        self.coord_scale)
c2937d9 by Walter Bender at 2010-08-12 2571
            else:
0dda146 by Walter Bender at 2013-06-25 2572
                spos = self.turtles.turtle_to_screen_coordinates(
2573
                    self.selected_turtle.get_xy())
2574
                dx = x - spos[0]
2575
                dy = y - spos[1]
2576
                self.turtles.get_active_turtle().set_heading(
2577
                    int(dragx + atan2(dy, dx) / DEGTOR + 5) / 10 * 10,
2578
                    share=False)
798b366 by Walter Bender at 2013-03-01 2579
                if self.update_counter % 5:
0dda146 by Walter Bender at 2013-06-25 2580
                    self.lc.update_label_value(
2581
                        'heading', self.selected_turtle.get_heading())
798b366 by Walter Bender at 2013-03-01 2582
            if self.update_counter % 20:
f5a2055 by Walter Bender at 2013-03-01 2583
                self.display_coordinates()
5ddf280 by Walter Bender at 2011-10-06 2584
            self.turtle_movement_to_share = self.selected_turtle
235bcc7 by Walter Bender at 2010-08-18 2585
c2937d9 by Walter Bender at 2010-08-12 2586
        # If we are hoving, show popup help.
2587
        elif self.drag_group is None:
2588
            self._show_popup(x, y)
2589
            return
235bcc7 by Walter Bender at 2010-08-18 2590
c2937d9 by Walter Bender at 2010-08-12 2591
        # If we have a stack of blocks selected, move them.
2592
        elif self.drag_group[0] is not None:
2593
            blk = self.drag_group[0]
235bcc7 by Walter Bender at 2010-08-18 2594
c2937d9 by Walter Bender at 2010-08-12 2595
            self.selected_spr = blk.spr
2596
            dragx, dragy = self.drag_pos
235bcc7 by Walter Bender at 2010-08-18 2597
            (sx, sy) = blk.spr.get_xy()
2598
            dx = x - dragx - sx
2599
            dy = y - dragy - sy
c2937d9 by Walter Bender at 2010-08-12 2600
9263b5c by Walter Bender at 2012-01-04 2601
            # Take no action if there was a move of 0, 0.
c2937d9 by Walter Bender at 2010-08-12 2602
            if dx == 0 and dy == 0:
2603
                return
28a6a8b by Walter Bender at 2010-08-19 2604
c2937d9 by Walter Bender at 2010-08-12 2605
            self.drag_group = find_group(blk)
2606
7496377 by Walter Bender at 2010-10-13 2607
            # Prevent blocks from ending up with a negative x or y
235bcc7 by Walter Bender at 2010-08-18 2608
            for blk in self.drag_group:
2609
                (bx, by) = blk.spr.get_xy()
c2937d9 by Walter Bender at 2010-08-12 2610
                if bx + dx < 0:
235bcc7 by Walter Bender at 2010-08-18 2611
                    dx = -bx
7496377 by Walter Bender at 2010-10-13 2612
                if by + dy < 0:
2613
                    dy = -by
c2937d9 by Walter Bender at 2010-08-12 2614
c58ae1b by Walter Bender at 2010-08-19 2615
            # Calculate a bounding box and only invalidate once.
28a6a8b by Walter Bender at 2010-08-19 2616
            minx = blk.spr.rect.x
2617
            miny = blk.spr.rect.y
2618
            maxx = blk.spr.rect.x + blk.spr.rect.width
2619
            maxy = blk.spr.rect.y + blk.spr.rect.height
a65346d by Walter Bender at 2010-08-19 2620
27dd7f8 by Walter Bender at 2010-08-18 2621
            for blk in self.drag_group:
2622
                if blk.spr.rect.x < minx:
2623
                    minx = blk.spr.rect.x
f4634c7 by Walter Bender at 2010-08-21 2624
                if blk.spr.rect.x + blk.spr.rect.width > maxx:
27dd7f8 by Walter Bender at 2010-08-18 2625
                    maxx = blk.spr.rect.x + blk.spr.rect.width
2626
                if blk.spr.rect.y < miny:
2627
                    miny = blk.spr.rect.y
f4634c7 by Walter Bender at 2010-08-21 2628
                if blk.spr.rect.y + blk.spr.rect.height > maxy:
27dd7f8 by Walter Bender at 2010-08-18 2629
                    maxy = blk.spr.rect.y + blk.spr.rect.height
2630
                blk.spr.rect.x += dx
2631
                blk.spr.rect.y += dy
2632
2633
            if dx < 0:
2634
                minx += dx
2635
            else:
2636
                maxx += dx
2637
            if dy < 0:
2638
                miny += dy
2639
            else:
2640
                maxy += dy
2641
2642
            self.rect.x = minx
2643
            self.rect.y = miny
2644
            self.rect.width = maxx - minx
2645
            self.rect.height = maxy - miny
ef080ed by Walter Bender at 2011-10-30 2646
            self.window.queue_draw_area(self.rect.x,
2647
                                        self.rect.y,
2648
                                        self.rect.width,
2649
                                        self.rect.height)
235bcc7 by Walter Bender at 2010-08-18 2650
        self.dx += dx
2651
        self.dy += dy
c2937d9 by Walter Bender at 2010-08-12 2652
2653
    def _show_popup(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 2654
        ''' Let's help our users by displaying a little help. '''
c2937d9 by Walter Bender at 2010-08-12 2655
        spr = self.sprite_list.find_sprite((x, y))
2656
        blk = self.block_list.spr_to_block(spr)
2657
        if spr and blk is not None:
11333ce by Walter Bender at 2013-05-22 2658
            if self._timeout_tag[0] == 0:
2659
                self._timeout_tag[0] = self._do_show_popup(blk.name)
c2937d9 by Walter Bender at 2010-08-12 2660
                self.selected_spr = spr
2661
            else:
11333ce by Walter Bender at 2013-05-22 2662
                if self._timeout_tag[0] > 0:
c2937d9 by Walter Bender at 2010-08-12 2663
                    try:
11333ce by Walter Bender at 2013-05-22 2664
                        gobject.source_remove(self._timeout_tag[0])
2665
                        self._timeout_tag[0] = 0
c2937d9 by Walter Bender at 2010-08-12 2666
                    except:
11333ce by Walter Bender at 2013-05-22 2667
                        self._timeout_tag[0] = 0
4fff361 by Walter Bender at 2013-05-22 2668
        elif spr and hasattr(spr, 'type') and \
2669
                (spr.type == 'selector' or
2670
                 spr.type == 'palette' or
2671
                 spr.type == 'toolbar'):
11333ce by Walter Bender at 2013-05-22 2672
            if self._timeout_tag[0] == 0 and hasattr(spr, 'name'):
2673
                self._timeout_tag[0] = self._do_show_popup(spr.name)
c2937d9 by Walter Bender at 2010-08-12 2674
                self.selected_spr = spr
2675
            else:
11333ce by Walter Bender at 2013-05-22 2676
                if self._timeout_tag[0] > 0:
c2937d9 by Walter Bender at 2010-08-12 2677
                    try:
11333ce by Walter Bender at 2013-05-22 2678
                        gobject.source_remove(self._timeout_tag[0])
2679
                        self._timeout_tag[0] = 0
c2937d9 by Walter Bender at 2010-08-12 2680
                    except:
11333ce by Walter Bender at 2013-05-22 2681
                        self._timeout_tag[0] = 0
c2937d9 by Walter Bender at 2010-08-12 2682
        else:
11333ce by Walter Bender at 2013-05-22 2683
            if self._timeout_tag[0] > 0:
c2937d9 by Walter Bender at 2010-08-12 2684
                try:
11333ce by Walter Bender at 2013-05-22 2685
                    gobject.source_remove(self._timeout_tag[0])
2686
                    self._timeout_tag[0] = 0
c2937d9 by Walter Bender at 2010-08-12 2687
                except:
11333ce by Walter Bender at 2013-05-22 2688
                    self._timeout_tag[0] = 0
c2937d9 by Walter Bender at 2010-08-12 2689
2690
    def _do_show_popup(self, block_name):
2fee6e6 by Walter Bender at 2012-06-23 2691
        ''' Fetch the help text and display it.  '''
69d7ba3 by Walter Bender at 2012-03-23 2692
        if self.no_help:
2693
            return 0
a9fb111 by Walter Bender at 2011-03-05 2694
        if block_name in special_names:
4b1f02e by Walter Bender at 2011-03-05 2695
            special_block_name = special_names[block_name]
a9fb111 by Walter Bender at 2011-03-05 2696
        elif block_name in block_names:
2467422 by Walter Bender at 2013-05-09 2697
            special_block_name = str(block_names[block_name][0])
c2937d9 by Walter Bender at 2010-08-12 2698
        elif block_name in TOOLBAR_SHAPES:
4b1f02e by Walter Bender at 2011-03-05 2699
            special_block_name = ''
c2937d9 by Walter Bender at 2010-08-12 2700
        else:
4b1f02e by Walter Bender at 2011-03-05 2701
            special_block_name = _(block_name)
2702
        if block_name in help_strings:
69d7ba3 by Walter Bender at 2012-03-23 2703
            label = help_strings[block_name]
c2937d9 by Walter Bender at 2010-08-12 2704
        else:
4b1f02e by Walter Bender at 2011-03-05 2705
            label = special_block_name
1742992 by Walter Bender at 2012-03-23 2706
        if self.last_label == label:
2707
            return 0
69d7ba3 by Walter Bender at 2012-03-23 2708
        self.showlabel('help', label=label)
1742992 by Walter Bender at 2012-03-23 2709
        self.last_label = label
c2937d9 by Walter Bender at 2010-08-12 2710
        return 0
2711
2712
    def _buttonrelease_cb(self, win, event):
2fee6e6 by Walter Bender at 2012-06-23 2713
        ''' Button release '''
c2937d9 by Walter Bender at 2010-08-12 2714
        x, y = xy(event)
57dc446 by Walter Bender at 2011-11-20 2715
        self.mouse_flag = 0
f968c54 by Walter Bender at 2011-11-17 2716
        self.mouse_x = x
2717
        self.mouse_y = y
c2937d9 by Walter Bender at 2010-08-12 2718
        self.button_release(x, y)
5ddf280 by Walter Bender at 2011-10-06 2719
        if self.turtle_movement_to_share is not None:
2720
            self._share_mouse_move()
c2937d9 by Walter Bender at 2010-08-12 2721
        return True
2722
f649ef8 by Walter Bender at 2010-08-18 2723
    def button_release(self, x, y):
4dfcb24 by Walter Bender at 2012-04-18 2724
        if self.running_sugar and self.dragging_canvas[0]:
2ca3c1f by Walter Bender at 2013-02-22 2725
            if self.dragging_counter > 0:
2726
                self.activity.adjust_sw(self.dragging_dx, self.dragging_dy)
2727
            self.dragging_counter = 0
2728
            self.dragging_dx = 0
2729
            self.dragging_dy = 0
60d0d9c by Walter Bender at 2012-04-10 2730
            self.dragging_canvas[0] = False
2731
            self.dragging_canvas[1] = x
2732
            self.dragging_canvas[2] = y
2733
            self.activity.adjust_palette()
2734
            return True
2735
c2937d9 by Walter Bender at 2010-08-12 2736
        # We may have been moving the turtle
2737
        if self.selected_turtle is not None:
0dda146 by Walter Bender at 2013-06-25 2738
            pos = self.selected_turtle.get_xy()
2739
            spos = self.turtles.turtle_to_screen_coordinates(pos)
2740
            turtle_name = self.turtles.get_turtle_key(self.selected_turtle)
7b697bd by Walter Bender at 2010-08-21 2741
            # Remove turtles by dragging them onto the trash palette.
0dda146 by Walter Bender at 2013-06-25 2742
            if self._in_the_trash(spos[0], spos[1]):
b374e3b by Walter Bender at 2010-09-08 2743
                # If it is the default turtle, just recenter it.
0dda146 by Walter Bender at 2013-06-25 2744
                if turtle_name == self.turtles.get_default_turtle_name():
138a327 by Walter Bender at 2010-08-23 2745
                    self._move_turtle(0, 0)
0dda146 by Walter Bender at 2013-06-25 2746
                    self.selected_turtle.set_heading(0)
2747
                    self.lc.update_label_value('heading', 0)
138a327 by Walter Bender at 2010-08-23 2748
                else:
2749
                    self.selected_turtle.hide()
0dda146 by Walter Bender at 2013-06-25 2750
                    self.turtles.remove_from_dict(turtle_name)
2751
                    self.turtles.set_active_turtle(None)
7b697bd by Walter Bender at 2010-08-21 2752
            else:
0dda146 by Walter Bender at 2013-06-25 2753
                self._move_turtle(pos[0], pos[1])
2754
c2937d9 by Walter Bender at 2010-08-12 2755
            self.selected_turtle = None
0dda146 by Walter Bender at 2013-06-25 2756
            if self.turtles.get_active_turtle() is None:
2757
                self.turtles.set_turtle(self.turtles.get_default_turtle_name())
007b114 by Walter Bender at 2013-03-01 2758
            self.display_coordinates()
c2937d9 by Walter Bender at 2010-08-12 2759
            return
2760
2761
        # If we don't have a group of blocks, then there is nothing to do.
dcd7408 by Walter Bender at 2010-10-10 2762
        if self.drag_group is None:
c2937d9 by Walter Bender at 2010-08-12 2763
            return
2764
2765
        blk = self.drag_group[0]
488c101 by Walter Bender at 2012-02-16 2766
        # Remove blocks by dragging them onto any palette.
c2937d9 by Walter Bender at 2010-08-12 2767
        if self.block_operation == 'move' and self._in_the_trash(x, y):
2768
            self._put_in_trash(blk, x, y)
2769
            self.drag_group = None
2770
            return
2771
2772
        # Pull a stack of new blocks off of the category palette.
2773
        if self.block_operation == 'new':
2774
            for gblk in self.drag_group:
2775
                (bx, by) = gblk.spr.get_xy()
2776
                if self.orientation == 0:
dcd7408 by Walter Bender at 2010-10-10 2777
                    gblk.spr.move((bx + 20,
2778
                                   by + PALETTE_HEIGHT + self.toolbar_offset))
c2937d9 by Walter Bender at 2010-08-12 2779
                else:
dcd7408 by Walter Bender at 2010-10-10 2780
                    gblk.spr.move((bx + PALETTE_WIDTH, by + 20))
c2937d9 by Walter Bender at 2010-08-12 2781
2782
        # Look to see if we can dock the current stack.
2783
        self._snap_to_dock()
2784
        for gblk in self.drag_group:
2785
            if gblk.status != 'collapsed':
2786
                gblk.spr.set_layer(BLOCK_LAYER)
2787
        self.drag_group = None
2788
2789
        # Find the block we clicked on and process it.
9263b5c by Walter Bender at 2012-01-04 2790
        # Consider a very small move a click (for touch interfaces)
2791
        if self.block_operation == 'click' or \
4fff361 by Walter Bender at 2013-05-22 2792
           (self.hw in [XO175, XO30, XO4] and
7eb786c by Walter Bender at 2012-12-23 2793
            self.block_operation == 'move' and (
11333ce by Walter Bender at 2013-05-22 2794
                abs(self.dx) < _MOTION_THRESHOLD and
2795
                abs(self.dy < _MOTION_THRESHOLD))):
c2937d9 by Walter Bender at 2010-08-12 2796
            self._click_block(x, y)
ea57633 by Walter Bender at 2012-06-30 2797
        elif self.block_operation == 'copying':
031d8f5 by Walter Bender at 2012-06-30 2798
            gobject.timeout_add(500, self._unhighlight_drag_group, blk)
2799
2800
    def _unhighlight_drag_group(self, blk):
4fff361 by Walter Bender at 2013-05-22 2801
        self.drag_group = find_group(blk)
2802
        for gblk in self.drag_group:
2803
            gblk.unhighlight()
2804
        self.drag_group = None
c2937d9 by Walter Bender at 2010-08-12 2805
e39c136 by Walter Bender at 2011-03-13 2806
    def remote_turtle(self, name):
2807
        ''' Is this a remote turtle? '''
2808
        if name == self.nick:
2809
            return False
36f997b by Walter Bender at 2011-03-14 2810
        if hasattr(self, 'remote_turtle_dictionary') and \
4fff361 by Walter Bender at 2013-05-22 2811
                name in self.remote_turtle_dictionary:
e39c136 by Walter Bender at 2011-03-13 2812
            return True
2813
        return False
2814
36f997b by Walter Bender at 2011-03-14 2815
    def label_remote_turtle(self, name, colors=['#A0A0A0', '#C0C0C0']):
bde0306 by Walter Bender at 2011-03-13 2816
        ''' Add a label to remote turtles '''
2817
        turtle = self.turtles.get_turtle(name)
2818
        if turtle is not None:
2819
            turtle.label_block = Block(self.block_list,
4fff361 by Walter Bender at 2013-05-22 2820
                                       self.sprite_list,
2821
                                       'turtle-label',
2822
                                       0,
2823
                                       0,
2824
                                       'label',
2825
                                       [],
2826
                                       2.0 / self.scale,
36f997b by Walter Bender at 2011-03-14 2827
                                       colors)
ca2875a by Walter Bender at 2012-06-10 2828
            turtle.label_block.spr.set_label_attributes(12.0 / self.scale)
1da7f3c by Walter Bender at 2011-03-17 2829
            if len(name) > 6:
2830
                turtle.label_block.spr.set_label(name[0:4] + '…')
fe5a555 by Walter Bender at 2011-03-17 2831
            else:
2832
                turtle.label_block.spr.set_label(name)
0dda146 by Walter Bender at 2013-06-25 2833
            turtle.set_remote()
bde0306 by Walter Bender at 2011-03-13 2834
            turtle.show()
2835
138a327 by Walter Bender at 2010-08-23 2836
    def _move_turtle(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 2837
        ''' Move the selected turtle to (x, y). '''
0dda146 by Walter Bender at 2013-06-25 2838
        if self.drag_turtle[0] == 'move':
2839
            self.turtles.get_active_turtle().move_turtle((x, y))
48cd6cf by Walter Bender at 2012-05-08 2840
        if self.interactive_mode:
138a327 by Walter Bender at 2010-08-23 2841
            self.display_coordinates()
48cd6cf by Walter Bender at 2012-05-08 2842
        if self.running_sugar:
138a327 by Walter Bender at 2010-08-23 2843
            self.selected_turtle.spr.set_layer(TURTLE_LAYER)
0dda146 by Walter Bender at 2013-06-25 2844
            self.lc.update_label_value(
2845
                'xcor', self.turtles.get_active_turtle().get_xy()[0] /
2846
                self.coord_scale)
2847
            self.lc.update_label_value(
2848
                'ycor', self.turtles.get_active_turtle().get_xy()[1] /
2849
                self.coord_scale)
138a327 by Walter Bender at 2010-08-23 2850
c2937d9 by Walter Bender at 2010-08-12 2851
    def _click_block(self, x, y):
2fee6e6 by Walter Bender at 2012-06-23 2852
        ''' Click block: lots of special cases to handle... '''
c2937d9 by Walter Bender at 2010-08-12 2853
        blk = self.block_list.spr_to_block(self.selected_spr)
2854
        if blk is None:
2855
            return
2856
        self.selected_blk = blk
17e51b8 by Walter Bender at 2010-11-23 2857
e8f85f0 by Walter Bender at 2012-10-24 2858
        if blk.name in ['string', 'number']:
2859
            self._saved_string = blk.spr.labels[0]
2860
            if not hasattr(self, '_text_entry'):
2861
                self._text_entry = gtk.TextView()
2862
                self._text_entry.set_justification(gtk.JUSTIFY_CENTER)
2863
                self._text_buffer = self._text_entry.get_buffer()
c83fa3c by Walter Bender at 2012-10-25 2864
                font_desc = pango.FontDescription('Sans')
54f85f2 by Walter Bender at 2012-10-30 2865
                font_desc.set_size(
2866
                    int(blk.font_size[0] * pango.SCALE * self.entry_scale))
c83fa3c by Walter Bender at 2012-10-25 2867
                self._text_entry.modify_font(font_desc)
e8f85f0 by Walter Bender at 2012-10-24 2868
                self.activity.fixed.put(self._text_entry, 0, 0)
2869
            self._text_entry.show()
2870
            w = blk.spr.label_safe_width()
4273124 by Walter Bender at 2012-11-28 2871
            if blk.name == 'string':
2872
                count = self._saved_string.count(RETURN)
2873
                self._text_buffer.set_text(
2874
                    self._saved_string.replace(RETURN, '\12'))
2875
                h = blk.spr.label_safe_height() * (count + 1)
2876
            else:
2877
                self._text_buffer.set_text(self._saved_string)
2878
                h = blk.spr.label_safe_height()
e8f85f0 by Walter Bender at 2012-10-24 2879
            self._text_entry.set_size_request(w, h)
2880
            bx, by = blk.spr.get_xy()
2881
            if not self.running_sugar:
2882
                by += self.activity.menu_height + 4  # FIXME: padding
2883
            mx, my = blk.spr.label_left_top()
54f85f2 by Walter Bender at 2012-10-30 2884
            self._text_entry.set_pixels_above_lines(my)
357da6f by Walter Bender at 2012-11-11 2885
            bx -= int(self.activity.sw.get_hadjustment().get_value())
2886
            by -= int(self.activity.sw.get_vadjustment().get_value())
e8f85f0 by Walter Bender at 2012-10-24 2887
            self.activity.fixed.move(self._text_entry, bx + mx, by + my * 2)
2888
            self.activity.fixed.show()
1cd797e by Walter Bender at 2012-11-27 2889
            if blk.name == 'number':
2890
                self._insert_text_id = self._text_buffer.connect(
2891
                    'insert-text', self._insert_text_cb)
e8f85f0 by Walter Bender at 2012-10-24 2892
            self._focus_out_id = self._text_entry.connect(
2893
                'focus-out-event', self._text_focus_out_cb)
2894
            self._text_entry.grab_focus()
17e51b8 by Walter Bender at 2010-11-23 2895
a9fb111 by Walter Bender at 2011-03-05 2896
        elif blk.name in block_styles['box-style-media'] and \
4fff361 by Walter Bender at 2013-05-22 2897
                blk.name not in NO_IMPORT:
c2937d9 by Walter Bender at 2010-08-12 2898
            self._import_from_journal(self.selected_blk)
2899
            if blk.name == 'journal' and self.running_sugar:
2900
                self._load_description_block(blk)
17e51b8 by Walter Bender at 2010-11-23 2901
c2937d9 by Walter Bender at 2010-08-12 2902
        elif blk.name == 'identity2' or blk.name == 'hspace':
2903
            group = find_group(blk)
2904
            if hide_button_hit(blk.spr, x, y):
c7f10c2 by Walter Bender at 2012-07-07 2905
                dx = -20
2906
                blk.contract_in_x(-dx)
2907
                # dx = blk.reset_x()
c2937d9 by Walter Bender at 2010-08-12 2908
            elif show_button_hit(blk.spr, x, y):
7b4847c by Walter Bender at 2010-09-23 2909
                dx = 20
c2937d9 by Walter Bender at 2010-08-12 2910
                blk.expand_in_x(dx)
2911
            else:
632bb2f by Walter Bender at 2011-04-20 2912
                self._run_stack(blk)
2913
                return
c2937d9 by Walter Bender at 2010-08-12 2914
            for gblk in group:
2915
                if gblk != blk:
2916
                    gblk.spr.move_relative((dx * blk.scale, 0))
17e51b8 by Walter Bender at 2010-11-23 2917
c2937d9 by Walter Bender at 2010-08-12 2918
        elif blk.name == 'vspace':
2919
            group = find_group(blk)
2920
            if hide_button_hit(blk.spr, x, y):
c7f10c2 by Walter Bender at 2012-07-07 2921
                dy = -20
2922
                blk.contract_in_y(-dy)
2923
                # dy = blk.reset_y()
c2937d9 by Walter Bender at 2010-08-12 2924
            elif show_button_hit(blk.spr, x, y):
2925
                dy = 20
2926
                blk.expand_in_y(dy)
2927
            else:
632bb2f by Walter Bender at 2011-04-20 2928
                self._run_stack(blk)
2929
                return
c2937d9 by Walter Bender at 2010-08-12 2930
            for gblk in group:
2931
                if gblk != blk:
2932
                    gblk.spr.move_relative((0, dy * blk.scale))
ecb658d by Walter Bender at 2012-07-06 2933
            self._resize_parent_clamps(blk)
17e51b8 by Walter Bender at 2010-11-23 2934
a9fb111 by Walter Bender at 2011-03-05 2935
        elif blk.name in expandable_blocks:
94d6dc8 by Walter Bender at 2010-09-20 2936
            # Connection may be lost during expansion, so store it...
2937
            blk0 = blk.connections[0]
2938
            if blk0 is not None:
2939
                dock0 = blk0.connections.index(blk)
2940
7f262d5 by Walter Bender at 2010-09-16 2941
            if hide_button_hit(blk.spr, x, y):
c7f10c2 by Walter Bender at 2012-07-07 2942
                dy = -20
2943
                blk.contract_in_y(-dy)
2944
                # dy = blk.reset_y()
7f262d5 by Walter Bender at 2010-09-16 2945
            elif show_button_hit(blk.spr, x, y):
2946
                dy = 20
2947
                blk.expand_in_y(dy)
2948
            else:
4adfa54 by Walter Bender at 2010-09-16 2949
                self._run_stack(blk)
1755db9 by Walter Bender at 2010-09-20 2950
                return
2951
39d5dcd by Walter Bender at 2011-04-21 2952
            if blk.name in block_styles['boolean-style']:
1ef0aba by Walter Bender at 2012-02-02 2953
                self._expand_boolean(blk, blk.connections[2], dy)
0a0583a by Walter Bender at 2010-09-22 2954
            else:
2955
                self._expand_expandable(blk, blk.connections[1], dy)
bc7b989 by Walter Bender at 2010-09-22 2956
94d6dc8 by Walter Bender at 2010-09-20 2957
            # and restore it...
2958
            if blk0 is not None:
2959
                blk.connections[0] = blk0
2960
                blk0.connections[dock0] = blk
2961
                self._cascade_expandable(blk)
2962
ecb658d by Walter Bender at 2012-07-06 2963
            self._resize_parent_clamps(blk)
1755db9 by Walter Bender at 2010-09-20 2964
a4828b6 by Walter Bender at 2010-09-17 2965
        elif blk.name in EXPANDABLE_ARGS or blk.name == 'nop':
c2937d9 by Walter Bender at 2010-08-12 2966
            if show_button_hit(blk.spr, x, y):
2967
                n = len(blk.connections)
dcd7408 by Walter Bender at 2010-10-10 2968
                group = find_group(blk.connections[n - 1])
c2937d9 by Walter Bender at 2010-08-12 2969
                if blk.name == 'myfunc1arg':
2970
                    blk.spr.labels[1] = 'f(x, y)'
2971
                    blk.spr.labels[2] = ' '
2972
                    dy = blk.add_arg()
2973
                    blk.primitive = 'myfunction2'
2974
                    blk.name = 'myfunc2arg'
2975
                elif blk.name == 'myfunc2arg':
2976
                    blk.spr.labels[1] = 'f(x, y, z)'
2977
                    dy = blk.add_arg(False)
2978
                    blk.primitive = 'myfunction3'
2979
                    blk.name = 'myfunc3arg'
2980
                elif blk.name == 'userdefined':
2981
                    dy = blk.add_arg()
2982
                    blk.primitive = 'userdefined2'
2983
                    blk.name = 'userdefined2args'
b153df0 by Walter Bender at 2011-03-19 2984
                    self._resize_skin(blk)
c2937d9 by Walter Bender at 2010-08-12 2985
                elif blk.name == 'userdefined2args':
2986
                    dy = blk.add_arg(False)
2987
                    blk.primitive = 'userdefined3'
2988
                    blk.name = 'userdefined3args'
b153df0 by Walter Bender at 2011-03-19 2989
                    self._resize_skin(blk)
cb84083 by Walter Bender at 2012-07-19 2990
                elif blk.name == 'loadblock':
2991
                    dy = blk.add_arg()
2992
                    blk.primitive = 'loadblock2'
2993
                    blk.name = 'loadblock2arg'
2994
                    self._resize_skin(blk)
2995
                elif blk.name == 'loadblock2arg':
2996
                    dy = blk.add_arg(False)
2997
                    blk.primitive = 'loadblock3'
2998
                    blk.name = 'loadblock3arg'
2999
                    self._resize_skin(blk)
c2937d9 by Walter Bender at 2010-08-12 3000
                else:
3001
                    dy = blk.add_arg()
3002
                for gblk in group:
3003
                    gblk.spr.move_relative((0, dy))
dcd7408 by Walter Bender at 2010-10-10 3004
                blk.connections.append(blk.connections[n - 1])
3005
                argname = blk.docks[n - 1][0]
4fff361 by Walter Bender at 2013-05-22 3006
                argvalue = default_values[blk.name][
3007
                    len(default_values[blk.name]) - 1]
c2937d9 by Walter Bender at 2010-08-12 3008
                argblk = Block(self.block_list, self.sprite_list, argname,
3009
                               0, 0, 'block', [argvalue], self.block_scale)
3010
                argdock = argblk.docks[0]
3011
                (bx, by) = blk.spr.get_xy()
3012
                nx = bx + blk.docks[n - 1][2] - argdock[2]
3013
                ny = by + blk.docks[n - 1][3] - argdock[3]
3014
                argblk.spr.move((nx, ny))
3015
                argblk.spr.set_layer(TOP_LAYER)
3016
                argblk.connections = [blk, None]
3017
                blk.connections[n - 1] = argblk
a9fb111 by Walter Bender at 2011-03-05 3018
                if blk.name in block_styles['number-style-var-arg']:
bc7b989 by Walter Bender at 2010-09-22 3019
                    self._cascade_expandable(blk)
ecb658d by Walter Bender at 2012-07-06 3020
                self._resize_parent_clamps(blk)
8657fd5 by Walter Bender at 2010-11-16 3021
            elif blk.name in PYTHON_SKIN:
c2937d9 by Walter Bender at 2010-08-12 3022
                self._import_py()
3023
            else:
3024
                self._run_stack(blk)
6c56adb by Walter Bender at 2012-07-05 3025
        elif blk.name == 'sandwichclampcollapsed':
3026
            restore_clamp(blk)
3027
            if blk.connections[1] is not None:
3028
                self._resize_clamp(blk, blk.connections[1], 1)
3029
            self._resize_parent_clamps(blk)
3030
        elif blk.name == 'sandwichclamp':
3031
            if hide_button_hit(blk.spr, x, y):
3032
                collapse_clamp(blk, True)
3033
                self._resize_parent_clamps(blk)
3034
            else:
3035
                self._run_stack(blk)
c2937d9 by Walter Bender at 2010-08-12 3036
        else:
3037
            self._run_stack(blk)
3038
6c56adb by Walter Bender at 2012-07-05 3039
    def _resize_parent_clamps(self, blk):
3040
        ''' If we changed size, we need to let any parent clamps know. '''
3041
        nblk, dockn = self._expandable_flow_above(blk)
3042
        while nblk is not None:
3043
            self._resize_clamp(nblk, nblk.connections[dockn], dockn=dockn)
3044
            nblk, dockn = self._expandable_flow_above(nblk)
3045
1daba0c by Walter Bender at 2010-09-20 3046
    def _expand_boolean(self, blk, blk2, dy):
2fee6e6 by Walter Bender at 2012-06-23 3047
        ''' Expand a boolean blk if blk2 is too big to fit. '''
1daba0c by Walter Bender at 2010-09-20 3048
        group = find_group(blk2)
3049
        for gblk in find_group(blk):
3050
            if gblk not in group:
3051
                gblk.spr.move_relative((0, -dy * blk.scale))
3052
3053
    def _expand_expandable(self, blk, blk2, dy):
2fee6e6 by Walter Bender at 2012-06-23 3054
        ''' Expand an expandable blk if blk2 is too big to fit. '''
1daba0c by Walter Bender at 2010-09-20 3055
        if blk2 is None:
3056
            group = [blk]
3057
        else:
3058
            group = find_group(blk2)
3059
            group.append(blk)
3060
        for gblk in find_group(blk):
3061
            if gblk not in group:
3062
                gblk.spr.move_relative((0, dy * blk.scale))
9a44aa9 by Walter Bender at 2012-02-16 3063
        if blk.name in block_styles['compare-style'] or \
4fff361 by Walter Bender at 2013-05-22 3064
                blk.name in block_styles['compare-porch-style']:
1daba0c by Walter Bender at 2010-09-20 3065
            for gblk in find_group(blk):
3066
                gblk.spr.move_relative((0, -dy * blk.scale))
3067
3ca64b6 by Walter Bender at 2011-03-02 3068
    def _number_style(self, name):
a9fb111 by Walter Bender at 2011-03-05 3069
        if name in block_styles['number-style']:
3ca64b6 by Walter Bender at 2011-03-02 3070
            return True
a9fb111 by Walter Bender at 2011-03-05 3071
        if name in block_styles['number-style-porch']:
3ca64b6 by Walter Bender at 2011-03-02 3072
            return True
a9fb111 by Walter Bender at 2011-03-05 3073
        if name in block_styles['number-style-block']:
3ca64b6 by Walter Bender at 2011-03-02 3074
            return True
a9fb111 by Walter Bender at 2011-03-05 3075
        if name in block_styles['number-style-var-arg']:
3ca64b6 by Walter Bender at 2011-03-02 3076
            return True
3077
        return False
3078
94d6dc8 by Walter Bender at 2010-09-20 3079
    def _cascade_expandable(self, blk):
2fee6e6 by Walter Bender at 2012-06-23 3080
        ''' If expanding/shrinking a block, cascade. '''
3ca64b6 by Walter Bender at 2011-03-02 3081
        while self._number_style(blk.name):
1daba0c by Walter Bender at 2010-09-20 3082
            if blk.connections[0] is None:
3083
                break
a9fb111 by Walter Bender at 2011-03-05 3084
            if blk.connections[0].name in expandable_blocks:
02ff768 by Walter Bender at 2010-09-22 3085
                if blk.connections[0].connections.index(blk) != 1:
3086
                    break
1daba0c by Walter Bender at 2010-09-20 3087
                blk = blk.connections[0]
bc7b989 by Walter Bender at 2010-09-22 3088
                if blk.connections[1].name == 'myfunc2arg':
06c8599 by Walter Bender at 2010-09-23 3089
                    dy = 40 + blk.connections[1].ey - blk.ey
bc7b989 by Walter Bender at 2010-09-22 3090
                elif blk.connections[1].name == 'myfunc3arg':
06c8599 by Walter Bender at 2010-09-23 3091
                    dy = 60 + blk.connections[1].ey - blk.ey
bc7b989 by Walter Bender at 2010-09-22 3092
                else:
06c8599 by Walter Bender at 2010-09-23 3093
                    dy = 20 + blk.connections[1].ey - blk.ey
1daba0c by Walter Bender at 2010-09-20 3094
                blk.expand_in_y(dy)
3095
                if dy != 0:
3096
                    group = find_group(blk.connections[1])
3097
                    group.append(blk)
3098
                    for gblk in find_group(blk):
3099
                        if gblk not in group:
3100
                            gblk.spr.move_relative((0, dy * blk.scale))
9a44aa9 by Walter Bender at 2012-02-16 3101
                    if blk.name in block_styles['compare-style'] or \
4fff361 by Walter Bender at 2013-05-22 3102
                            blk.name in block_styles['compare-porch-style']:
1daba0c by Walter Bender at 2010-09-20 3103
                        for gblk in find_group(blk):
3104
                            gblk.spr.move_relative((0, -dy * blk.scale))
997d7e9 by Walter Bender at 2010-09-22 3105
            else:
3106
                break
1daba0c by Walter Bender at 2010-09-20 3107
c2937d9 by Walter Bender at 2010-08-12 3108
    def _run_stack(self, blk):
2fee6e6 by Walter Bender at 2012-06-23 3109
        ''' Run a stack of blocks. '''
5e1e531 by Walter Bender at 2013-01-16 3110
        if not self.interactive_mode:
3111
            # Test for forever block
3112
            if len(self.block_list.get_similar_blocks('block', 'forever')) > 0:
3113
                debug_output('WARNING: Projects with forever blocks \
4fff361 by Walter Bender at 2013-05-22 3114
 may not terminate.', False)
8d09405 by Walter Bender at 2012-10-19 3115
        if self.status_spr is not None:
3116
            self.status_spr.hide()
3117
        self._autohide_shape = True
c2937d9 by Walter Bender at 2010-08-12 3118
        if blk is None:
3119
            return
c658e47 by Walter Bender at 2011-04-08 3120
        self.lc.find_value_blocks()  # Are there blocks to update?
12eab0c by Walter Bender at 2013-07-06 3121
        if self.canvas.cr_svg is None:
3122
            self.canvas.setup_svg_surface()
8c22cc8 by Walter Bender at 2012-06-02 3123
        self.running_blocks = True
c658e47 by Walter Bender at 2011-04-08 3124
        self._start_plugins()  # Let the plugins know we are running.
c2937d9 by Walter Bender at 2010-08-12 3125
        top = find_top_block(blk)
edf6d46 by Walter Bender at 2013-03-21 3126
        code = self.lc.generate_code(top, self.just_blocks())
3127
        self.lc.run_blocks(code)
c2937d9 by Walter Bender at 2010-08-12 3128
        if self.interactive_mode:
3129
            gobject.idle_add(self.lc.doevalstep)
3130
        else:
3131
            while self.lc.doevalstep():
3132
                pass
3133
3134
    def _snap_to_dock(self):
2fee6e6 by Walter Bender at 2012-06-23 3135
        ''' Snap a block (selected_block) to the dock of another block
4fff361 by Walter Bender at 2013-05-22 3136
        (destination_block). '''
94d6dc8 by Walter Bender at 2010-09-20 3137
        selected_block = self.drag_group[0]
3138
        best_destination = None
11333ce by Walter Bender at 2013-05-22 3139
        d = _SNAP_THRESHOLD
7f1f1c9 by Walter Bender at 2012-07-02 3140
        self.inserting_block_mid_stack = False
94d6dc8 by Walter Bender at 2010-09-20 3141
        for selected_block_dockn in range(len(selected_block.docks)):
3fdf592 by Walter Bender at 2010-09-20 3142
            for destination_block in self.just_blocks():
ae39e44 by Walter Bender at 2011-11-03 3143
                # Don't link to a block that is hidden
3144
                if destination_block.status == 'collapsed':
3145
                    continue
3fdf592 by Walter Bender at 2010-09-20 3146
                # Don't link to a block to which you're already connected
3147
                if destination_block in self.drag_group:
c2937d9 by Walter Bender at 2010-08-12 3148
                    continue
3fdf592 by Walter Bender at 2010-09-20 3149
                # Check each dock of destination for a possible connection
3150
                for destination_dockn in range(len(destination_block.docks)):
7f1f1c9 by Walter Bender at 2012-07-02 3151
                    this_xy = self.dock_dx_dy(
3152
                        destination_block, destination_dockn,
3153
                        selected_block, selected_block_dockn)
c2937d9 by Walter Bender at 2010-08-12 3154
                    if magnitude(this_xy) > d:
3155
                        continue
3156
                    d = magnitude(this_xy)
3157
                    best_xy = this_xy
3fdf592 by Walter Bender at 2010-09-20 3158
                    best_destination = destination_block
3159
                    best_destination_dockn = destination_dockn
94d6dc8 by Walter Bender at 2010-09-20 3160
                    best_selected_block_dockn = selected_block_dockn
11333ce by Walter Bender at 2013-05-22 3161
        if d < _SNAP_THRESHOLD:
ba24e48 by Walter Bender at 2012-02-02 3162
            # Some combinations of blocks are not valid
94d6dc8 by Walter Bender at 2010-09-20 3163
            if not arithmetic_check(selected_block, best_destination,
3164
                                    best_selected_block_dockn,
3fdf592 by Walter Bender at 2010-09-20 3165
                                    best_destination_dockn):
c2937d9 by Walter Bender at 2010-08-12 3166
                return
291f55f by Walter Bender at 2010-09-23 3167
            if not journal_check(selected_block, best_destination,
4fff361 by Walter Bender at 2013-05-22 3168
                                 best_selected_block_dockn,
3169
                                 best_destination_dockn):
291f55f by Walter Bender at 2010-09-23 3170
                return
ba24e48 by Walter Bender at 2012-02-02 3171
3172
            # Move the selected blocks into the docked position
c2937d9 by Walter Bender at 2010-08-12 3173
            for blk in self.drag_group:
3174
                (sx, sy) = blk.spr.get_xy()
3175
                blk.spr.move((sx + best_xy[0], sy + best_xy[1]))
3176
3fdf592 by Walter Bender at 2010-09-20 3177
            blk_in_dock = best_destination.connections[best_destination_dockn]
7f1f1c9 by Walter Bender at 2012-07-02 3178
            if self.inserting_block_mid_stack:
3179
                # If there was already a block docked there, move it
3180
                # to the bottom of the drag group.
3181
                if blk_in_dock is not None and blk_in_dock != selected_block:
3182
                    bot = find_bot_block(self.drag_group[0])
3183
                    if bot is not None:
3184
                        blk_in_dock.connections[0] = None
3185
                        drag_group = find_group(blk_in_dock)
3186
                        blk_in_dock.connections[0] = bot
3187
                        bot.connections[-1] = blk_in_dock
3188
                        dx = bot.spr.get_xy()[0] - \
4fff361 by Walter Bender at 2013-05-22 3189
                            self.drag_group[0].spr.get_xy()[0] + \
3190
                            bot.docks[-1][2] - blk_in_dock.docks[0][2]
7f1f1c9 by Walter Bender at 2012-07-02 3191
                        dy = bot.spr.get_xy()[1] - \
4fff361 by Walter Bender at 2013-05-22 3192
                            self.drag_group[0].spr.get_xy()[1] + \
3193
                            bot.docks[-1][3] - blk_in_dock.docks[0][3]
7f1f1c9 by Walter Bender at 2012-07-02 3194
                        # Move each sprite in the group associated
3195
                        # with the block we are moving.
3196
                        for gblk in drag_group:
3197
                            gblk.spr.move_relative((dx, dy))
3198
            else:
3199
                # If there was already a block docked there, move it
3200
                # to the trash.
3201
                if blk_in_dock is not None and blk_in_dock != selected_block:
3202
                    blk_in_dock.connections[0] = None
3203
                    self._put_in_trash(blk_in_dock)
c2937d9 by Walter Bender at 2010-08-12 3204
ba24e48 by Walter Bender at 2012-02-02 3205
            # Note the connection in destination dock
94d6dc8 by Walter Bender at 2010-09-20 3206
            best_destination.connections[best_destination_dockn] = \
3207
                selected_block
ba24e48 by Walter Bender at 2012-02-02 3208
3209
            # And in the selected block dock
94d6dc8 by Walter Bender at 2010-09-20 3210
            if selected_block.connections is not None:
ddd48d3 by Walter Bender at 2010-10-15 3211
                if best_selected_block_dockn < len(selected_block.connections):
3212
                    selected_block.connections[best_selected_block_dockn] = \
3213
                        best_destination
c2937d9 by Walter Bender at 2010-08-12 3214
679bf36 by Walter Bender at 2012-07-25 3215
            # Are we renaming an action or variable?
3216
            if best_destination.name in ['hat', 'storein'] and \
4fff361 by Walter Bender at 2013-05-22 3217
                    selected_block.name == 'string' and \
3218
                    best_destination_dockn == 1:
679bf36 by Walter Bender at 2012-07-25 3219
                name = selected_block.values[0]
3220
                if best_destination.name == 'storein':
3221
                    if not self._find_proto_name('storein_%s' % (name), name):
3222
                        self._new_storein_block(name)
3223
                    if not self._find_proto_name('box_%s' % (name), name):
3224
                        self._new_box_block(name)
3225
                else:  # 'hat'
3226
                    # Check to see if it is unique...
3227
                    unique = True
3228
                    similars = self.block_list.get_similar_blocks(
3229
                        'block', 'hat')
3230
                    for blk in similars:
3231
                        if blk == best_destination:
3232
                            continue
3233
                        if blk.connections is not None and \
4fff361 by Walter Bender at 2013-05-22 3234
                                blk.connections[1] is not None and \
3235
                                blk.connections[1].name == 'string':
3236
                            if blk.connections[1].values[0] == name:
679bf36 by Walter Bender at 2012-07-25 3237
                                unique = False
3238
                    if not unique:
3239
                        while self._find_proto_name('stack_%s' % (name), name):
3240
                            name = increment_name(name)
3241
                        blk.connections[1].values[0] = name
3242
                        blk.connections[1].spr.labels[0] = name
3243
                        blk.resize()
3244
                    self._new_stack_block(name)
3245
ba24e48 by Walter Bender at 2012-02-02 3246
            # Some destination blocks expand to accomodate large blocks
a9fb111 by Walter Bender at 2011-03-05 3247
            if best_destination.name in block_styles['boolean-style']:
1daba0c by Walter Bender at 2010-09-20 3248
                if best_destination_dockn == 2 and \
4fff361 by Walter Bender at 2013-05-22 3249
                        (selected_block.name in
3250
                         block_styles['boolean-style'] or