class Block:
    """ A class for the individual blocks
    
    Attributes:
    docks -- a list of docks, i.e. connection points where other blocks
        could be attached. Each dock is a list of the form
        [type_of_dock, flow_is_in, x, y, parenthesis]
        with the last element being optional.
        type_of_dock may be one of the following strings:
            flow -- connect to the previous or next block ('slot' or 'tab')
            bool, media, number, string -- argument slot ('innie') or
                return value ('outie') of the given kind
            unavailable -- nothing can be attached here ('cap' or 'tail')
        flow_is_in is True if the flow is into the block, or False for out.
        x and y are coodinates for positioning the block on the dock.
        parenthesis is only used with arguments and ensures a known order
            of arguments for arithmetic and logical operations.
    connections -- a list of blocks that are attached to this one (or that
        this one is attached to). This list corresponds to the docks list
        as it uses the same indices. Slots where nothing is attached are
        None on this list.
    primitive -- a callable that is called when the block is executed
    type -- type of the block:
        block -- block that is part of the user's program
        proto -- block on a palette, used to generate other blocks
        trash -- block in the trash """

    def __init__(self, block_list, sprite_list, name, x, y, type='block',
                 values=[], scale=BLOCK_SCALE[0],
                 colors=['#A0A0A0', '#808080']):

        self.block_list = block_list
        self.spr = None
        self.shapes = [None, None]
        self.name = name
        self.colors = colors
        self._custom_colors = False
        self.scale = scale
        self.docks = None
        self.connections = None
        self.status = None
        self.values = []
        self.primitive = None
        self.type = type
        self.dx = 0
        self.ex = 0
        self.ey = 0
        self.ey2 = 0
        self._ei = 0
        self.font_size = [6.0, 4.5]
        self._image = None
        self._visible = True
        self.unknown = False  # Block is of unknown style

        self.block_methods = {
            'basic-style': self._make_basic_style,
            'blank-style': self._make_blank_style,
            'basic-style-head': self._make_basic_style_head,
            'basic-style-head-1arg': self._make_basic_style_head_1arg,
            'basic-style-tail': self._make_basic_style_tail,
            'basic-style-extended': [self._make_basic_style, 16, 16],
            'basic-style-extended-vertical': [self._make_basic_style, 0, 4],
            'basic-style-1arg': self._make_basic_style_1arg,
            'basic-style-2arg': self._make_basic_style_2arg,
            'basic-style-3arg': self._make_basic_style_3arg,
            'basic-style-var-arg': self._make_basic_style_var_arg,
            'bullet-style': self._make_bullet_style,
            'box-style': self._make_box_style,
            'box-style-media': self._make_media_style,
            'number-style': self._make_number_style,
            'number-style-block': self._make_number_style_block,
            'number-style-porch': self._make_number_style_porch,
            'number-style-1arg': self._make_number_style_1arg,
            'number-style-1strarg': self._make_number_style_1strarg,
            'number-style-var-arg': self._make_number_style_var_arg,
            'compare-style': self._make_compare_style,
            'compare-porch-style': self._make_compare_porch_style,
            'boolean-style': self._make_boolean_style,
            'not-style': self._make_not_style,
            'boolean-block-style': self._make_boolean_block_style,
            'boolean-1arg-block-style': self._make_boolean_1arg_block_style,
            'clamp-style': self._make_clamp_style,
            'clamp-style-collapsible': self._make_clamp_style_collapsible,
            'clamp-style-collapsed': self._make_clamp_style_collapsed,
            'clamp-style-1arg': self._make_clamp_style_1arg,
            'clamp-style-boolean': self._make_clamp_style_boolean,
            'clamp-style-else': self._make_clamp_style_else,
            'flow-style-tail': self._make_flow_style_tail,
            'portfolio-style-2x2': self._make_portfolio_style_2x2,
            'portfolio-style-1x1': self._make_portfolio_style_1x1,
            'portfolio-style-2x1': self._make_portfolio_style_2x1,
            'portfolio-style-1x2': self._make_portfolio_style_1x2}

        if self.name in OLD_NAMES:
            self.name = OLD_NAMES[self.name]

        for i in range(len(self.font_size)):
            self.font_size[i] *= self.scale * \
                self.block_list.font_scale_factor

        for v in (values):
            self.values.append(v)

        # If there is already a block with the same name, reuse it
        copy_block = None
        if self.cloneable():
            for b in self.block_list.list:
                if b.scale == self.scale and b.name == self.name:
                    copy_block = b
                    break
        self._new_block_from_factory(sprite_list, x, y, copy_block)

        if name in block_primitives:
            self.primitive = block_primitives[self.name]

        self.block_list.append_to_list(self)

    def get_visibility(self):
        ''' Should block be visible on the palette? '''
        return self._visible

    def set_visibility(self, state):
        ''' Should block be visible? '''
        self._visible = state
        if self._visible:
            self.spr.restore()
        else:
            self.spr.hide()

    def expandable(self):
        """ Can this block be expanded? """
        if self.name in EXPANDABLE:
            return True
        if self.name in expandable_blocks:
            return True
        if self.name in EXPANDABLE_ARGS:
            return True
        if self.name in EXPANDABLE_FLOW:
            return True
        return False

    def cloneable(self):
        """ Is it safe to clone this block? """
        if self.expandable():
            return False
        if self.name in block_styles['box-style']:
            return False
        if self.name in ['storein', 'box', 'string',
                         # Deprecated blocks
                         'sandwichtop', 'sandwichtop_no_label']:
            return False
        return True

    def highlight(self):
        """ We may want to highlight a block... """
        if self.spr is not None and self.status is not 'collapsed':
            self.spr.set_shape(self.shapes[1])

    def unhighlight(self):
        """ Or unhighlight it. """
        if self.spr is not None and self.status is not 'collapsed':
            self.spr.set_shape(self.shapes[0])

    def resize(self):
        """ We need to resize some blocks on the fly so the labels fit. """
        if self.spr is None:
            return
        dx = (self.spr.label_width() - self.spr.label_safe_width()) / \
            self.scale
        if self.dx + dx >= self.block_list.max_width and \
           self.name == 'string':
            self.dx = self.block_list.max_width
            self.refresh()
            self._set_labels(0, self.spr.labels[0])
        elif dx != 0:
            self.dx += dx
            if self.dx < 0:
                self.dx = 0
            self.refresh()

    def set_image(self, image, x, y):
        """ Some blocks get a skin. """
        if self.spr is None:
            return
        self._image = image
        self.spr.set_image(image, 1, x, y)

    def scale_image(self, x, y, w, h):
        """ The skin might need scaling. """
        if self.spr is None:
            return
        if self._image is not None:
            tmp = self._image.scale_simple(w, h, gtk.gdk.INTERP_NEAREST)
            self.spr.set_image(tmp, 1, x, y)

    def rescale(self, scale):
        """ We may want to rescale blocks as well. """
        if self.spr is None:
            return
        for i in range(len(self.font_size)):
            self.font_size[i] /= self.scale
        self.scale = scale
        for i in range(len(self.font_size)):
            self.font_size[i] *= self.scale
        self.svg.set_scale(self.scale)
        self.refresh()
        self.spr.inval()

    def set_colors(self, colors):
        self.colors = colors[:]
        self._custom_colors = True
        self.refresh()

    def refresh(self):
        if self.spr is None:
            return
        self._make_block(self.svg)
        self._set_margins()
        self._set_label_attributes()
        self.spr.set_shape(self.shapes[0])

    def add_arg(self, keep_expanding=True):
        """ We may want to add additional slots for arguments ("innies"). """
        if self.spr is None:
            return
        h = self.svg.get_height()
        self._ei += 1
        if self.type == 'block' and keep_expanding:
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return self.svg.get_height() - h

    def expand_in_y(self, dy):
        """ We may want to grow a block vertically. """
        if self.spr is None:
            return
        self.ey += dy
        if self.type == 'block':
            if self.ey > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def expand_in_y2(self, dy):
        """ We may want to grow a block vertically. """
        if self.spr is None:
            return
        self.ey2 += dy
        if self.type == 'block':
            if self.ey2 > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def expand_in_x(self, dx):
        """ We may want to grow a block horizontally. """
        if self.spr is None:
            return
        self.ex += dx
        if self.type == 'block':
            self.svg.set_hide(True)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def contract_in_y(self, dy):
        """ We may want to shrink a block veritcally. """
        if self.spr is None:
            return
        self.ey -= dy
        if self.ey < 0:
            self.ey = 0
        if self.type == 'block':
            if self.ey > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def contract_in_x(self, dx):
        """ We may want to shrink a block horizontally. """
        if self.spr is None:
            return
        self.ex -= dx
        if self.ex < 0:
            self.ex = 0
        if self.type == 'block':
            if self.ex > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def reset_x(self):
        if self.spr is None:
            return 0
        dx = -self.ex
        self.ex = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return dx

    def reset_y(self):
        if self.spr is None:
            return 0
        dy = -self.ey
        self.ey = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:  # 'proto'
            self.svg.set_show(False)
        self.refresh()
        return dy

    def reset_y2(self):
        if self.spr is None:
            return 0
        dy = -self.ey2
        self.ey2 = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:  # 'proto'
            self.svg.set_show(False)
        self.refresh()
        return dy

    def get_expand_x_y(self):
        if self.spr is None:
            return(0, 0)
        return (self.ex, self.ey, self.ey2)

    def _new_block_from_factory(self, sprite_list, x, y, copy_block=None):
        self.svg = SVG()
        self.svg.set_scale(self.scale)
        self.svg.set_innie([False])
        self.svg.set_outie(False)
        self.svg.set_tab(True)
        self.svg.set_slot(True)

        if copy_block is not None:
            self._left = copy_block._left
            self._top = copy_block._top
            self._right = copy_block._right
            self._bottom = copy_block._bottom
            self.dx = copy_block.dx
            self.ex = copy_block.ex
            self.ey = copy_block.ey
            self.width = copy_block.width
            self.height = copy_block.height
            self.shapes[0] = copy_block.shapes[0]
            if sprite_list is not None:
                self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
                self.spr._margins = copy_block.spr._margins[:]
            if len(copy_block.shapes) > 1:
                self.shapes[1] = copy_block.shapes[1]
            self.docks = copy_block.docks[:]
        else:
            if self.expandable() and self.type == 'block':
                self.svg.set_show(True)

            self._make_block(self.svg)

            if sprite_list is not None:
                self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
                self._set_margins()

        self._set_label_attributes()
        if (self.name == 'number' or self.name == 'string') and \
                len(self.values) > 0:
            for i, v in enumerate(self.values):
                if v is not None:
                    if self.name == 'number':
                        self._set_labels(i,
                           str(v).replace('.', self.block_list.decimal_point))
                    else:
                        self._set_labels(i, str(v))
        elif self.type == 'block' and self.name in CONSTANTS:
            if CONSTANTS[self.name] in COLORDICT:
                v = COLORDICT[CONSTANTS[self.name]][0]
                if v is None:
                    v = COLORDICT[CONSTANTS[self.name]][1]
            else:
                v = CONSTANTS[self.name]
            self._set_labels(0, block_names[self.name][0] + ' = ' + str(v))

        elif self.name in block_names:
            for i, n in enumerate(block_names[self.name]):
                self._set_labels(i, n)

        if copy_block is None and self.spr is not None:
            if self.spr.label_width() > self.spr.label_safe_width():
                self.resize()

    def _set_margins(self):
        if self.spr is None:
            return
        self.spr.set_margins(self.svg.margins[0], self.svg.margins[1],
                             self.svg.margins[2], self.svg.margins[3])

    def _set_label_attributes(self):
        if self.spr is None:
            return
        if isinstance(self.name, unicode):
            self.name = self.name.encode('utf-8')
        if self.name in content_blocks:
            n = len(self.values)
            if n == 0:
                n = 1  # Force a scale to be set, even if there is no value.
        else:
            if self.name in block_names:
                n = len(block_names[self.name])
            else:
                debug_output('WARNING: unknown block name %s' % (self.name))
                n = 0
        for i in range(n):
            if i > 0:
                size = int(self.font_size[1] + 0.5)
            else:
                size = int(self.font_size[0] + 0.5)
            if self.name in block_styles['compare-porch-style']:
                self.spr.set_label_attributes(size, True, 'center', 'bottom',
                                              i=i)
            elif self.name in block_styles['number-style-porch']:
                self.spr.set_label_attributes(size, True, 'right', 'bottom',
                                              i=i)
            elif self.name in EXPANDABLE_FLOW:
                self._calc_moving_labels(i)
            elif self.name == 'string':
                self.spr.set_label_attributes(size, False, 'center', 'middle')
            elif i == 1:  # top
                self.spr.set_label_attributes(size, True, 'right', 'top', i=i)
            elif i > 0 and i == n - 1:  # bottom
                self.spr.set_label_attributes(size, True, 'right', 'bottom',
                                              i=i)
            elif i > 0:
                self.spr.set_label_attributes(size, True, 'right', 'middle',
                                              i=i)
            else:
                self.spr.set_label_attributes(size, True, 'center', 'middle',
                                              i=i)

    def _calc_moving_labels(self, i):
        ''' Some labels move as blocks change shape/size '''
        if self.name in block_styles['clamp-style'] or \
           self.name in block_styles['clamp-style-collapsible']:
            y = int((self.docks[0][3] + self.docks[1][3]) / 3.3)
            self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
                                          True, 'right', y_pos=y, i=0)
        elif self.name in block_styles['clamp-style-1arg']:
            y = self.docks[1][3] - int(int(self.font_size[0] * 1.3))
            self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
                                          True, 'right', y_pos=y, i=0)
        elif self.name in block_styles['clamp-style-boolean']:
            y = self.docks[1][3] - int(int(self.font_size[0] * 1.3))
            self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
                                          True, 'right', y_pos=y, i=0)
            y = self.docks[2][3] - int(int(self.font_size[0] * 1.9))
            self.spr.set_label_attributes(int(self.font_size[1] + 0.5),
                                          True, 'right', y_pos=y, i=1)
        elif self.name in block_styles['clamp-style-else']:
            y = self.docks[1][3] - int(int(self.font_size[0] * 1.3))
            self.spr.set_label_attributes(int(self.font_size[0] + 0.5),
                                          True, 'right', y_pos=y, i=0)
            y = self.docks[2][3] - int(int(self.font_size[0] * 1.9))
            self.spr.set_label_attributes(int(self.font_size[1] + 0.5),
                                          True, 'right', y_pos=y, i=1)
            y = self.docks[3][3] - int(int(self.font_size[0] * 1.45))
            self.spr.set_label_attributes(int(self.font_size[1] + 0.5),
                                          True, 'right', y_pos=y, i=2)


    def _set_labels(self, i, label):
        if self.spr is None:
            return
        self.spr.set_label(label, i)

    def _make_block(self, svg):
        self._left = 0
        self._top = 0
        self._right = 0
        self._bottom = 0
        self.svg.set_stroke_width(STANDARD_STROKE_WIDTH)
        self.svg.clear_docks()
        if isinstance(self.name, unicode):
            self.name = self.name.encode('utf-8')
        for k in block_styles.keys():
            if self.name in block_styles[k]:
                if isinstance(self.block_methods[k], list):
                    self.block_methods[k][0](svg, self.block_methods[k][1],
                                             self.block_methods[k][2])
                else:
                    self.block_methods[k](svg)
                return
        error_output('ERROR: block type not found %s' % (self.name))
        self.block_methods['blank-style'](svg)
        self.unknown = True

    def _set_colors(self, svg):
        if self._custom_colors:
            self.svg.set_colors(self.colors)
            return
        if self.name in BOX_COLORS:
            self.colors = BOX_COLORS[self.name]
        elif self.name in special_block_colors:
            self.colors = special_block_colors[self.name]
        else:
            for p in range(len(palette_blocks)):
                if self.name in palette_blocks[p]:
                    self.colors = block_colors[p]
        self.svg.set_colors(self.colors)

    def _make_basic_style(self, svg, extend_x=0, extend_y=0):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                       self.svg.docks[0][1]], ['flow',
                       False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_blank_style(self, svg, extend_x=0, extend_y=0):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(False)
        self.svg.set_tab(False)
        self.svg.set_tail(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = []

    def _make_basic_style_head(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['unavailable', False, 0, 0],
                      ['flow', False, self.svg.docks[0][0],
                                      self.svg.docks[0][1]]]

    def _make_basic_style_head_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['unavailable', False, 0, 0],
                      ['string', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_basic_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_tab(False)
        self.svg.set_tail(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_basic_style_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_basic_style_2arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]]]

    def _make_basic_style_3arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True, True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]],
                      ['number', False, self.svg.docks[3][0],
                                        self.svg.docks[3][1]],
                      ['flow', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]]]

    def _make_basic_style_var_arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]
        for i in range(self._ei):
            self.docks.append(['number', False, self.svg.docks[i + 2][0],
                                                self.svg.docks[i + 2][1]])
        self.docks.append(['flow', False, self.svg.docks[self._ei + 2][0],
                                      self.svg.docks[self._ei + 2][1]])

    def _make_bullet_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True, True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1], '['],
                      ['string', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]]]
        for i in range(self._ei):
            self.docks.append(['string', False, self.svg.docks[i + 3][0],
                                                self.svg.docks[i + 3][1]])
        self.docks.append(['flow', False, self.svg.docks[self._ei + 3][0],
                                      self.svg.docks[self._ei + 3][1], ']'])

    def _make_box_style(self, svg):
        self.svg.expand(60 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [['number', True, self.svg.docks[0][0],
                                       self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_media_style(self, svg):
        self.svg.expand(40 + self.dx + self.ex, 10 + self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [['number', True, self.svg.docks[0][0],
                                       self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_number_style(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        """
        NOTE: The "outie" is added last, so the dock order in NUMBER_STYLE
              blocks needs to be modified.
        """
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]

    def _make_number_style_var_arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei + 1):
            innie.append(True)
        self.svg.set_innie(innie)
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2 + self._ei][0],
                                       self.svg.docks[2 + self._ei][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]]]
        for i in range(self._ei + 1):
            self.docks.append(['number', False, self.svg.docks[i + 1][0],
                                                self.svg.docks[i + 1][1]])
        self.docks.append(['unavailable', False, 0, 0])

    def _make_number_style_block(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1], '('],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['unavailable', False, 0, 0, ')']]

    def _make_number_style_1arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[1][0],
                                       self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]]]

    def _make_number_style_1strarg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[1][0],
                                       self.svg.docks[1][1]],
                      ['string', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_number_style_porch(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self.svg.set_porch(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]

    def _make_compare_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_compare)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1], '('],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]],
                      ['unavailable', False, 0, 0, ')']]

    def _make_compare_porch_style(self, svg):
        self.svg.set_porch(True)
        self._make_compare_style(svg)

    def _make_boolean_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_and_or)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['bool', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_not_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_not, arg=False)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_boolean_block_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_not, arg=True)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_boolean_1arg_block_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.boolean_not, arg=True)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]

    def _make_clamp_style(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.second_clamp(False)
        self._make_block_graphics(svg, self.svg.clamp)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1], '['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], ']']]

    def _make_clamp_style_collapsible(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_collapsible(True)
        self.svg.second_clamp(False)
        self._make_block_graphics(svg, self.svg.clamp)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1], '['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], ']']]

    def _make_clamp_style_collapsed(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_show(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                       self.svg.docks[0][1]],
                      ['unavailable', True, 0, self.svg.docks[0][1] + 10, '['],
                      ['flow', False, self.svg.docks[1][0],
                       self.svg.docks[1][1], ']']]

    def _make_clamp_style_1arg(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True])
        self.svg.second_clamp(False)
        self._make_block_graphics(svg, self.svg.clamp)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], '['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1], ']']]

    def _make_clamp_style_boolean(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_boolean(True)
        self.svg.second_clamp(False)
        self._make_block_graphics(svg, self.svg.clamp)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], '['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1], ']']]

    def _make_clamp_style_else(self, svg, extend_x=0, extend_y=4):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y,
                        self.dx + self.ex + extend_x, self.ey2 + extend_y)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_boolean(True)
        self.svg.second_clamp(True)
        self._make_block_graphics(svg, self.svg.clamp)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], '['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1], ']['],
                      # Skip bottom of clamp
                      ['flow', False, self.svg.docks[6][0],
                                      self.svg.docks[6][1], ']']]

    def _make_flow_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(False)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    # Depreciated block styles

    def _make_portfolio_style_2x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[6][0],
                                      self.svg.docks[6][1]],
                      ['media', False, self.svg.docks[5][0],
                                      self.svg.docks[5][1]],
                      ['media', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['media', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]]]

    def _make_portfolio_style_2x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_portfolio_style_1x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_portfolio_style_1x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_block_graphics(self, svg, function, arg=None):
        self._set_colors(svg)
        self.svg.set_gradient(True, GRADIENT_COLOR)
        if arg is None:
            pixbuf = svg_str_to_pixbuf(function())
        else:
            pixbuf = svg_str_to_pixbuf(function(arg))
        self.width = self.svg.get_width()
        self.height = self.svg.get_height()
        self.shapes[0] = _pixbuf_to_cairo_surface(pixbuf,
                                                  self.width, self.height)
        self.svg.set_gradient(False)
        if arg is None:
            pixbuf = svg_str_to_pixbuf(function())
        else:
            pixbuf = svg_str_to_pixbuf(function(arg))
        self.shapes[1] = _pixbuf_to_cairo_surface(pixbuf,
                                                  self.width, self.height)
Example #2
0
class Block:
    """ A class for the individual blocks """

    def __init__(self, block_list, sprite_list, name, x, y, type='block',
                 values=[], scale=BLOCK_SCALE, colors=["#FF0000", "#A00000"]):
        self.block_list = block_list
        self.spr = None
        self.shapes = [None, None]
        self.name = name
        self.colors = colors
        self.scale = scale
        self.docks = None
        self.connections = None
        self.status = None
        self.values = []
        self.primitive = None
        self.type = type
        self.dx = 0
        self.ex = 0
        self.ey = 0
        self._ei = 0
        self._font_size = [6.0, 4.5]
        self._image = None

        if self.name in OLD_NAMES:
            self.name = OLD_NAMES[self.name]

        for i in range(len(self._font_size)):
            self._font_size[i] *= self.scale * \
                self.block_list.font_scale_factor

        for v in (values):
            self.values.append(v)

        # If there is already a block with the same name, reuse it
        copy_block = None
        if self.name not in EXPANDABLE and \
           self.name not in EXPANDABLE_BLOCKS and \
           self.name not in EXPANDABLE_ARGS and \
           self.name not in ['string', 'sandwichtop', 'sandwichtop_no_label']:
            for b in self.block_list.list:
                if b.scale == self.scale and b.name == self.name:
                    copy_block = b
                    break
        self._new_block_from_factory(sprite_list, x, y, copy_block)

        if name in PRIMITIVES:
            self.primitive = PRIMITIVES[self.name]

        self.block_list.append_to_list(self)

    def highlight(self):
        """ We may want to highlight a block... """
        if self.spr is not None:
            self.spr.set_shape(self.shapes[1])

    def unhighlight(self):
        """ Or unhighlight it. """
        if self.spr is not None:
            self.spr.set_shape(self.shapes[0])

    def resize(self):
        """ We need to resize some blocks on the fly so the labels fit. """
        if self.spr is None:
            return
        dx = (self.spr.label_width() - self.spr.label_safe_width()) / \
            self.scale
        if dx !=0:
            self.dx += dx
            if self.dx < 0:
                self.dx = 0
            self.refresh()

    def set_image(self, image, x, y):
        """ Some blocks get a skin. """
        if self.spr is None:
            return
        self._image = image
        self.spr.set_image(image, 1, x, y)

    def scale_image(self, x, y, w, h):
        """ The skin might need scaling. """
        if self.spr is None:
            return
        if self._image is not None:
            tmp = self._image.scale_simple(w, h, gtk.gdk.INTERP_NEAREST)
            self.spr.set_image(tmp, 1, x, y)

    def rescale(self, scale):
        """ We may want to rescale blocks as well. """
        if self.spr is None:
            return
        for i in range(len(self._font_size)):
            self._font_size[i] /= self.scale
        self.scale = scale
        for i in range(len(self._font_size)):
            self._font_size[i] *= self.scale
        self._set_label_attributes()
        self.svg.set_scale(self.scale)
        self.refresh()
        self.spr.draw()

    def refresh(self):
        if self.spr is None:
            return
        self._make_block(self.svg)
        self._set_margins()
        self.spr.set_shape(self.shapes[0])

    def add_arg(self, keep_expanding=True):
        """ We may want to add additional slots for arguments ("innies"). """
        if self.spr is None:
            return
        h = self.svg.get_height()
        self._ei += 1
        if self.type == 'block' and keep_expanding:
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return self.svg.get_height() - h

    def expand_in_y(self, dy):
        """ We may want to grow a block vertically. """
        if self.spr is None:
            return
        self.ey += dy
        if self.type == 'block':
            if self.ey > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def expand_in_x(self, dx):
        """ We may want to grow a block horizontally. """
        if self.spr is None:
            return
        self.ex += dx
        if self.type == 'block':
            self.svg.set_hide(True)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def reset_x(self):
        if self.spr is None:
            return 0
        dx = -self.ex
        self.ex = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return dx

    def reset_y(self):
        if self.spr is None:
            return 0
        dy = -self.ey
        self.ey = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else: # 'proto'
            self.svg.set_show(False)
        self.refresh()
        return dy

    def get_expand_x_y(self):
        if self.spr is None:
            return(0, 0)
        return (self.ex, self.ey)

    def _new_block_from_factory(self, sprite_list, x, y, copy_block=None):

        self.svg = SVG()
        self.svg.set_scale(self.scale)
        self.svg.set_gradiant(True)
        self.svg.set_innie([False])
        self.svg.set_outie(False)
        self.svg.set_tab(True)
        self.svg.set_slot(True)

        if copy_block is not None:
            self._left = copy_block._left
            self._top = copy_block._top
            self._right = copy_block._right
            self._bottom = copy_block._bottom
            self.dx = copy_block.dx
            self.ex = copy_block.ex
            self.ey = copy_block.ey
            self.width = copy_block.width
            self.height = copy_block.height
            self.shapes[0] = copy_block.shapes[0]
            self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
            self.spr._margins = copy_block.spr._margins[:]
            if len(copy_block.shapes) > 1:
                self.shapes[1] = copy_block.shapes[1]
            self.docks = copy_block.docks[:]
        else:
            if (self.name in EXPANDABLE or \
                self.name in EXPANDABLE_BLOCKS or \
                self.name in EXPANDABLE_ARGS) and \
               self.type == 'block':
                self.svg.set_show(True)

            self._make_block(self.svg)

            if sprite_list is not None:
                self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
                self._set_margins()

        self._set_label_attributes()
        if (self.name == 'number' or self.name == 'string') and \
                len(self.values) > 0:
            for i, v in enumerate(self.values):
                if v is not None:
                    if self.name == 'number':
                        self._set_labels(i,
                           str(v).replace('.', self.block_list.decimal_point))
                    else:
                        self._set_labels(i, str(v))
        elif self.name in BLOCK_NAMES:
            for i, n in enumerate(BLOCK_NAMES[self.name]):
                self._set_labels(i, n)

        if copy_block is None:
            if self.spr.label_width() > self.spr.label_safe_width():
                self.resize()

    def _set_margins(self):
        self.spr.set_margins(self.svg.margins[0], self.svg.margins[1],
                             self.svg.margins[2], self.svg.margins[3])

    def _set_label_attributes(self):
        if self.name in CONTENT_BLOCKS:
            n = len(self.values)
            if n == 0:
                n = 1 # Force a scale to be set, even if there is no value.
        else:
            n = len(BLOCK_NAMES[self.name])
        for i in range(n):
            if i == 1: # top
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'top', i)
            elif i == 2: # bottom
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'bottom', i)
            else:
                self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
                                              True, 'center', 'middle', i)

    def _set_labels(self, i, label):
        self.spr.set_label(label, i)

    def _make_block(self, svg):
        self._left = 0
        self._top = 0
        self._right = 0
        self._bottom = 0
        self._set_colors(svg)
        self.svg.set_stroke_width(STANDARD_STROKE_WIDTH)
        self.svg.clear_docks()
        if self.name in BASIC_STYLE:
            self._make_basic_style(svg)
        elif self.name in BASIC_STYLE_HEAD:
            self._make_basic_style_head(svg)
        elif self.name in BASIC_STYLE_EXTENDED:
            self._make_basic_style(svg, 16, 16)
        elif self.name in BASIC_STYLE_EXTENDED_VERTICAL:
            self._make_basic_style(svg, 0, 4)
        elif self.name in BASIC_STYLE_HEAD_1ARG:
            self._make_basic_style_head_1arg(svg)
        elif self.name in BASIC_STYLE_TAIL:
            self._make_basic_style_tail(svg)
        elif self.name in BASIC_STYLE_1ARG:
            self._make_basic_style_1arg(svg)
        elif self.name in BASIC_STYLE_2ARG:
            self._make_basic_style_2arg(svg)
        elif self.name in BASIC_STYLE_VAR_ARG:
            self._make_basic_style_var_arg(svg)
        elif self.name in BULLET_STYLE:
            self._make_bullet_style(svg)
        elif self.name in BOX_STYLE:
            self._make_box_style(svg)
        elif self.name in BOX_STYLE_MEDIA:
            self._make_media_style(svg)
        elif self.name in NUMBER_STYLE:
            self._make_number_style(svg)
        elif self.name in NUMBER_STYLE_BLOCK:
            self._make_number_style_block(svg)
        elif self.name in NUMBER_STYLE_VAR_ARG:
            self._make_number_style_var_arg(svg)
        elif self.name in NUMBER_STYLE_1ARG:
            self._make_number_style_1arg(svg)
        elif self.name in NUMBER_STYLE_1STRARG:
            self._make_number_style_1strarg(svg)
        elif self.name in NUMBER_STYLE_PORCH:
            self._make_number_style_porch(svg)
        elif self.name in COMPARE_STYLE:
            self._make_compare_style(svg)
        elif self.name in BOOLEAN_STYLE:
            self._make_boolean_style(svg)
        elif self.name in NOT_STYLE:
            self._make_not_style(svg)
        elif self.name in FLOW_STYLE:
            self._make_flow_style(svg)
        elif self.name in FLOW_STYLE_TAIL:
            self._make_flow_style_tail(svg)
        elif self.name in FLOW_STYLE_1ARG:
            self._make_flow_style_1arg(svg)
        elif self.name in FLOW_STYLE_BOOLEAN:
            self._make_flow_style_boolean(svg)
        elif self.name in FLOW_STYLE_WHILE:
            self._make_flow_style_while(svg)
        elif self.name in FLOW_STYLE_ELSE:
            self._make_flow_style_else(svg)
        elif self.name in COLLAPSIBLE_TOP:
            self._make_collapsible_style_top(svg, arm=True, label=True)
        elif self.name in COLLAPSIBLE_TOP_NO_ARM:
            self._make_collapsible_style_top(svg, arm=False, label=True)
        elif self.name in COLLAPSIBLE_TOP_NO_LABEL:
            self._make_collapsible_style_top(svg, arm=True, label=False)
        elif self.name in COLLAPSIBLE_TOP_NO_ARM_NO_LABEL:
            self._make_collapsible_style_top(svg, arm=False, label=False)
        elif self.name in COLLAPSIBLE_BOTTOM:
            self._make_collapsible_style_bottom(svg)
        elif self.name in PORTFOLIO_STYLE_2x2:
            self._make_portfolio_style_2x2(svg)
        elif self.name in PORTFOLIO_STYLE_2x1:
            self._make_portfolio_style_2x1(svg)
        elif self.name in PORTFOLIO_STYLE_1x1:
            self._make_portfolio_style_1x1(svg)
        elif self.name in PORTFOLIO_STYLE_1x2:
            self._make_portfolio_style_1x2(svg)
        else:
            self._make_basic_style(svg)
            _logger.debug("WARNING: I don't know how to create a %s block" % \
                              (self.name))

    def _set_colors(self, svg):
        if self.name in BOX_COLORS:
            self.colors = BOX_COLORS[self.name]
        else:
            for p in range(len(PALETTES)):
                if self.name in PALETTES[p]:
                    self.colors = COLORS[p]
        self.svg.set_colors(self.colors)

    def _make_basic_style(self, svg, extend_x=0, extend_y=0):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                       self.svg.docks[0][1]], ['flow',
                       False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_basic_style_head(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['unavailable', False, 0, 0],
                      ['flow', False, self.svg.docks[0][0],
                                      self.svg.docks[0][1]]]

    def _make_basic_style_head_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['unavailable', False, 0, 0],
                      ['string', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_basic_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_tab(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_basic_style_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_basic_style_2arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]]]

    def _make_basic_style_var_arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]
        for i in range(self._ei):
            self.docks.append(['number', False, self.svg.docks[i + 2][0],
                                                self.svg.docks[i + 2][1]])
        self.docks.append(['flow', False, self.svg.docks[self._ei + 2][0],
                                      self.svg.docks[self._ei + 2][1]])

    def _make_bullet_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True, True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1], '['],
                      ['string', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]]]
        for i in range(self._ei):
            self.docks.append(['string', False, self.svg.docks[i + 3][0],
                                                self.svg.docks[i + 3][1]])
        self.docks.append(['flow', False, self.svg.docks[self._ei + 3][0],
                                      self.svg.docks[self._ei + 3][1], ']'])

    def _make_box_style(self, svg):
        self.svg.expand(60 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [['number', True, self.svg.docks[0][0],
                                       self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_media_style(self, svg):
        self.svg.expand(40 + self.dx + self.ex, 10 + self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [['number', True, self.svg.docks[0][0],
                                       self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_number_style(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        """
        NOTE: The "outie" is added last, so the dock order in NUMBER_STYLE
              blocks needs to be modified.
        """
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]

    def _make_number_style_var_arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei + 1):
            innie.append(True)
        self.svg.set_innie(innie)
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2 + self._ei][0],
                                       self.svg.docks[2 + self._ei][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]]]
        for i in range(self._ei + 1):
            self.docks.append(['number', False, self.svg.docks[i + 1][0],
                                                self.svg.docks[i + 1][1]])
        self.docks.append(['unavailable', False, 0, 0])

    def _make_number_style_block(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1], '('],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['unavailable', False, 0, 0, ')']]

    def _make_number_style_1arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[1][0],
                                       self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]]]

    def _make_number_style_1strarg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[1][0],
                                       self.svg.docks[1][1]],
                      ['string', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_number_style_porch(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self.svg.set_porch(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['number', True, self.svg.docks[2][0],
                                       self.svg.docks[2][1]],
                      ['number', False, self.svg.docks[0][0],
                                        self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]]]

    def _make_compare_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_compare)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1], '('],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['number', False, self.svg.docks[2][0],
                                        self.svg.docks[2][1]],
                      ['unavailable', False, 0, 0, ')']]

    def _make_boolean_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_and_or)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['bool', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_not_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_not)
        self.docks = [['bool', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_flow_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1], '['],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], ']']]

    def _make_flow_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(False)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_flow_style_1arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['number', False, self.svg.docks[1][0],
                                        self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], '['],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], ']']]

    def _make_flow_style_boolean(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_boolean(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], '['],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], ']']]

    def _make_flow_style_while(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_boolean(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1], '['],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], ']['],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], ']']]

    def _make_flow_style_else(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_else(True)
        self.svg.set_boolean(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['bool', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1], '['],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1], ']['],
                      ['flow', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1], ']']]

    def _make_collapsible_style_top(self, svg, arm=True, label=True):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_arm(arm)
        self._make_block_graphics(svg, self.svg.sandwich_top, label)
        if label:
            self.docks = [['flow', True, self.svg.docks[0][0],
                           self.svg.docks[0][1]],
                          ['number', False, self.svg.docks[1][0],
                           self.svg.docks[1][1]],
                          ['flow', False, self.svg.docks[2][0],
                           self.svg.docks[2][1]]]
        else:
            self.docks = [['flow', True, self.svg.docks[0][0],
                           self.svg.docks[0][1]],
                          ['flow', False, self.svg.docks[1][0],
                           self.svg.docks[1][1]]]

    def _make_collapsible_style_bottom(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.sandwich_bottom)
        self.docks = [['flow', True, self.svg.docks[0][0],
                       self.svg.docks[0][1]], ['flow', False,
                       self.svg.docks[1][0], self.svg.docks[1][1]]]

    # Depreciated block styles

    def _make_portfolio_style_2x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[6][0],
                                      self.svg.docks[6][1]],
                      ['media', False, self.svg.docks[5][0],
                                      self.svg.docks[5][1]],
                      ['media', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['media', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]]]

    def _make_portfolio_style_2x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]],
                      ['flow', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]]]

    def _make_portfolio_style_1x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[4][0],
                                      self.svg.docks[4][1]],
                      ['media', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_portfolio_style_1x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [['flow', True, self.svg.docks[0][0],
                                     self.svg.docks[0][1]],
                      ['string', False, self.svg.docks[3][0],
                                      self.svg.docks[3][1]],
                      ['media', False, self.svg.docks[2][0],
                                      self.svg.docks[2][1]],
                      ['flow', False, self.svg.docks[1][0],
                                      self.svg.docks[1][1]]]

    def _make_block_graphics(self, svg, function, arg=None):
        if arg is None:
            self.shapes[0] = svg_str_to_pixbuf(function())
        else:
            self.shapes[0] = svg_str_to_pixbuf(function(arg))
        self.width = self.svg.get_width()
        self.height = self.svg.get_height()
        self.svg.set_stroke_width(SELECTED_STROKE_WIDTH)
        self.svg.set_stroke_color(SELECTED_COLOR)
        if arg is None:
            self.shapes[1] = svg_str_to_pixbuf(function())
        else:
            self.shapes[1] = svg_str_to_pixbuf(function(arg))
Example #3
0
class Block:
    """ A class for the individual blocks """
    def __init__(self,
                 block_list,
                 sprite_list,
                 name,
                 x,
                 y,
                 type='block',
                 values=[],
                 scale=BLOCK_SCALE[0],
                 colors=['#A0A0A0', '#808080']):

        self.block_list = block_list
        self.spr = None
        self.shapes = [None, None]
        self.name = name
        self.colors = colors
        self._custom_colors = False
        self.scale = scale
        self.docks = None
        self.connections = None
        self.status = None
        self.values = []
        self.primitive = None
        self.type = type
        self.dx = 0
        self.ex = 0
        self.ey = 0
        self._ei = 0
        self._font_size = [6.0, 4.5]
        self._image = None
        self._visible = True

        self.block_methods = {
            'basic-style':
            self._make_basic_style,
            'blank-style':
            self._make_blank_style,
            'basic-style-head':
            self._make_basic_style_head,
            'basic-style-head-1arg':
            self._make_basic_style_head_1arg,
            'basic-style-tail':
            self._make_basic_style_tail,
            'basic-style-extended': [self._make_basic_style, 16, 16],
            'basic-style-extended-vertical': [self._make_basic_style, 0, 4],
            'basic-style-1arg':
            self._make_basic_style_1arg,
            'basic-style-2arg':
            self._make_basic_style_2arg,
            'basic-style-3arg':
            self._make_basic_style_3arg,
            'basic-style-var-arg':
            self._make_basic_style_var_arg,
            'invisible':
            self._make_invisible_style,
            'bullet-style':
            self._make_bullet_style,
            'box-style':
            self._make_box_style,
            'box-style-media':
            self._make_media_style,
            'number-style':
            self._make_number_style,
            'number-style-block':
            self._make_number_style_block,
            'number-style-porch':
            self._make_number_style_porch,
            'number-style-1arg':
            self._make_number_style_1arg,
            'number-style-1strarg':
            self._make_number_style_1strarg,
            'number-style-var-arg':
            self._make_number_style_var_arg,
            'compare-style':
            self._make_compare_style,
            'compare-porch-style':
            self._make_compare_porch_style,
            'boolean-style':
            self._make_boolean_style,
            'not-style':
            self._make_not_style,
            'flow-style':
            self._make_flow_style,
            'flow-style-tail':
            self._make_flow_style_tail,
            'flow-style-1arg':
            self._make_flow_style_1arg,
            'flow-style-boolean':
            self._make_flow_style_boolean,
            'flow-style-else':
            self._make_flow_style_else,
            'collapsible-top': [self._make_collapsible_style_top, True, True],
            'collapsible-top-no-arm':
            [self._make_collapsible_style_top, False, True],
            'collapsible-top-no-label':
            [self._make_collapsible_style_top, True, False],
            'collapsible-top-no-arm-no-label':
            [self._make_collapsible_style_top, False, False],
            'collapsible-bottom':
            self._make_collapsible_style_bottom,
            'portfolio-style-2x2':
            self._make_portfolio_style_2x2,
            'portfolio-style-1x1':
            self._make_portfolio_style_1x1,
            'portfolio-style-2x1':
            self._make_portfolio_style_2x1,
            'portfolio-style-1x2':
            self._make_portfolio_style_1x2
        }

        if self.name in OLD_NAMES:
            self.name = OLD_NAMES[self.name]

        for i in range(len(self._font_size)):
            self._font_size[i] *= self.scale * \
                self.block_list.font_scale_factor

        for v in (values):
            self.values.append(v)

        # If there is already a block with the same name, reuse it
        copy_block = None
        if self.cloneable():
            for b in self.block_list.list:
                if b.scale == self.scale and b.name == self.name:
                    copy_block = b
                    break
        self._new_block_from_factory(sprite_list, x, y, copy_block)

        if name in block_primitives:
            self.primitive = block_primitives[self.name]

        self.block_list.append_to_list(self)

    def get_visibility(self):
        ''' Should block be visible on the palette? '''
        return self._visible

    def set_visibility(self, state):
        ''' Should block be visible? '''
        self._visible = state
        if self._visible:
            self.spr.restore()
        else:
            self.spr.hide()

    def expandable(self):
        """ Can this block be expanded? """
        if self.name in EXPANDABLE:
            return True
        if self.name in expandable_blocks:
            return True
        if self.name in EXPANDABLE_ARGS:
            return True
        return False

    def cloneable(self):
        """ Is it safe to clone this block? """
        if self.expandable():
            return False
        if self.name in block_styles['box-style']:
            return False
        if self.name in ['sandwichtop', 'sandwichtop_no_label']:
            return False
        return True

    def highlight(self):
        """ We may want to highlight a block... """
        if self.spr is not None:
            self.spr.set_shape(self.shapes[1])

    def unhighlight(self):
        """ Or unhighlight it. """
        if self.spr is not None:
            self.spr.set_shape(self.shapes[0])

    def resize(self):
        """ We need to resize some blocks on the fly so the labels fit. """
        if self.spr is None:
            return
        dx = (self.spr.label_width() - self.spr.label_safe_width()) / \
            self.scale
        if dx != 0:
            self.dx += dx
            if self.dx < 0:
                self.dx = 0
            self.refresh()

    def set_image(self, image, x, y):
        """ Some blocks get a skin. """
        if self.spr is None:
            return
        self._image = image
        self.spr.set_image(image, 1, x, y)

    def scale_image(self, x, y, w, h):
        """ The skin might need scaling. """
        if self.spr is None:
            return
        if self._image is not None:
            tmp = self._image.scale_simple(w, h, gtk.gdk.INTERP_NEAREST)
            self.spr.set_image(tmp, 1, x, y)

    def rescale(self, scale):
        """ We may want to rescale blocks as well. """
        if self.spr is None:
            return
        for i in range(len(self._font_size)):
            self._font_size[i] /= self.scale
        self.scale = scale
        for i in range(len(self._font_size)):
            self._font_size[i] *= self.scale
        self._set_label_attributes()
        self.svg.set_scale(self.scale)
        self.refresh()
        self.spr.inval()

    def set_colors(self, colors):
        self.colors = colors[:]
        self._custom_colors = True
        self.refresh()

    def refresh(self):
        if self.spr is None:
            return
        self._make_block(self.svg)
        self._set_margins()
        self.spr.set_shape(self.shapes[0])

    def add_arg(self, keep_expanding=True):
        """ We may want to add additional slots for arguments ("innies"). """
        if self.spr is None:
            return
        h = self.svg.get_height()
        self._ei += 1
        if self.type == 'block' and keep_expanding:
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return self.svg.get_height() - h

    def expand_in_y(self, dy):
        """ We may want to grow a block vertically. """
        if self.spr is None:
            return
        self.ey += dy
        if self.type == 'block':
            if self.ey > 0:
                self.svg.set_hide(True)
            else:
                self.svg.set_hide(False)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def expand_in_x(self, dx):
        """ We may want to grow a block horizontally. """
        if self.spr is None:
            return
        self.ex += dx
        if self.type == 'block':
            self.svg.set_hide(True)
            self.svg.set_show(True)
        else:
            self.svg.set_hide(False)
            self.svg.set_show(False)
        self.refresh()

    def reset_x(self):
        if self.spr is None:
            return 0
        dx = -self.ex
        self.ex = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:
            self.svg.set_show(False)
        self.refresh()
        return dx

    def reset_y(self):
        if self.spr is None:
            return 0
        dy = -self.ey
        self.ey = 0
        self.svg.set_hide(False)
        if self.type == 'block':
            self.svg.set_show(True)
        else:  # 'proto'
            self.svg.set_show(False)
        self.refresh()
        return dy

    def get_expand_x_y(self):
        if self.spr is None:
            return (0, 0)
        return (self.ex, self.ey)

    def _new_block_from_factory(self, sprite_list, x, y, copy_block=None):
        self.svg = SVG()
        self.svg.set_scale(self.scale)
        self.svg.set_innie([False])
        self.svg.set_outie(False)
        self.svg.set_tab(True)
        self.svg.set_slot(True)

        if copy_block is not None:
            self._left = copy_block._left
            self._top = copy_block._top
            self._right = copy_block._right
            self._bottom = copy_block._bottom
            self.dx = copy_block.dx
            self.ex = copy_block.ex
            self.ey = copy_block.ey
            self.width = copy_block.width
            self.height = copy_block.height
            self.shapes[0] = copy_block.shapes[0]
            if sprite_list is not None:
                self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
                self.spr._margins = copy_block.spr._margins[:]
            if len(copy_block.shapes) > 1:
                self.shapes[1] = copy_block.shapes[1]
            self.docks = copy_block.docks[:]
        else:
            if self.expandable() and self.type == 'block':
                self.svg.set_show(True)

            self._make_block(self.svg)

            if sprite_list is not None:
                self.spr = sprites.Sprite(sprite_list, x, y, self.shapes[0])
                self._set_margins()

        self._set_label_attributes()
        if (self.name == 'number' or self.name == 'string') and \
                len(self.values) > 0:
            for i, v in enumerate(self.values):
                if v is not None:
                    if self.name == 'number':
                        self._set_labels(
                            i,
                            str(v).replace('.', self.block_list.decimal_point))
                    else:
                        self._set_labels(i, str(v))
        elif self.type == 'block' and self.name in CONSTANTS:
            self._set_labels(0, block_names[self.name][0] + ' = ' + \
                                 str(CONSTANTS[self.name]))

        elif self.name in block_names:
            for i, n in enumerate(block_names[self.name]):
                self._set_labels(i, n)

        if copy_block is None and self.spr is not None:
            if self.spr.label_width() > self.spr.label_safe_width():
                self.resize()

    def _set_margins(self):
        if self.spr is None:
            return
        self.spr.set_margins(self.svg.margins[0], self.svg.margins[1],
                             self.svg.margins[2], self.svg.margins[3])

    def _set_label_attributes(self):
        if self.spr is None:
            return
        if self.name in content_blocks:
            n = len(self.values)
            if n == 0:
                n = 1  # Force a scale to be set, even if there is no value.
        else:
            if self.name in block_names:
                n = len(block_names[self.name])
            else:
                debug_output('WARNING: unknown block name %s' % (self.name))
                n = 0
        for i in range(n):
            if self.name in block_styles['compare-porch-style']:
                self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
                                              True, 'center', 'bottom', i)
            elif self.name in block_styles['number-style-porch']:
                self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
                                              True, 'right', 'bottom', i)

            elif self.name in block_styles['flow-style-boolean'] or \
                 self.name in block_styles['flow-style-else']:
                self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
                                              True, 'left', 'middle', 0)
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'top', 1)
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'bottom', 2)
            elif i == 1:  # top
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'top', i)
            elif i == 2:  # bottom
                self.spr.set_label_attributes(int(self._font_size[1] + 0.5),
                                              True, 'right', 'bottom', i)
            else:
                self.spr.set_label_attributes(int(self._font_size[0] + 0.5),
                                              True, 'center', 'middle', i)

    def _set_labels(self, i, label):
        if self.spr is None:
            return
        self.spr.set_label(label, i)

    def _make_block(self, svg):
        self._left = 0
        self._top = 0
        self._right = 0
        self._bottom = 0
        self.svg.set_stroke_width(STANDARD_STROKE_WIDTH)
        self.svg.clear_docks()
        for k in block_styles.keys():
            if self.name in block_styles[k]:
                if type(self.block_methods[k]) == type([]):
                    self.block_methods[k][0](svg, self.block_methods[k][1],
                                             self.block_methods[k][2])
                else:
                    self.block_methods[k](svg)
                return
        error_output('block type not found %s' % (self.name))
        self.block_methods['basic-style'](svg)

    def _set_colors(self, svg):
        if self._custom_colors:
            self.svg.set_colors(self.colors)
            return
        if self.name in BOX_COLORS:
            self.colors = BOX_COLORS[self.name]
        elif self.name in special_block_colors:
            self.colors = special_block_colors[self.name]
        else:
            for p in range(len(palette_blocks)):
                if self.name in palette_blocks[p]:
                    self.colors = block_colors[p]
        self.svg.set_colors(self.colors)

    def _make_basic_style(self, svg, extend_x=0, extend_y=0):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_blank_style(self, svg, extend_x=0, extend_y=0):
        self.svg.expand(self.dx + self.ex + extend_x, self.ey + extend_y)
        self.svg.set_slot(False)
        self.svg.set_tab(False)
        self.svg.set_tail(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = []

    def _make_basic_style_head(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [['unavailable', False, 0, 0],
                      [
                          'flow', False, self.svg.docks[0][0],
                          self.svg.docks[0][1]
                      ]]

    def _make_basic_style_head_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_slot(False)
        self.svg.set_cap(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['unavailable', False, 0, 0],
            ['string', False, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]
        ]

    def _make_basic_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_tab(False)
        self.svg.set_tail(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['unavailable', False, 0, 0]]

    def _make_basic_style_1arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1]]
        ]

    def _make_basic_style_2arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['number', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['flow', False, self.svg.docks[3][0], self.svg.docks[3][1]]
        ]

    def _make_basic_style_3arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True, True])
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['number', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['number', False, self.svg.docks[3][0], self.svg.docks[3][1]],
            ['flow', False, self.svg.docks[4][0], self.svg.docks[4][1]]
        ]

    def _make_basic_style_var_arg(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]]]
        for i in range(self._ei):
            self.docks.append([
                'number', False, self.svg.docks[i + 2][0],
                self.svg.docks[i + 2][1]
            ])
        self.docks.append([
            'flow', False, self.svg.docks[self._ei + 2][0],
            self.svg.docks[self._ei + 2][1]
        ])

    def _make_bullet_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        innie = [True, True]
        for i in range(self._ei):
            innie.append(True)
        self.svg.set_innie(innie)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['string', False, self.svg.docks[1][0], self.svg.docks[1][1], '['],
            ['string', False, self.svg.docks[2][0], self.svg.docks[2][1]]
        ]
        for i in range(self._ei):
            self.docks.append([
                'string', False, self.svg.docks[i + 3][0],
                self.svg.docks[i + 3][1]
            ])
        self.docks.append([
            'flow', False, self.svg.docks[self._ei + 3][0],
            self.svg.docks[self._ei + 3][1], ']'
        ])

    def _make_box_style(self, svg):
        self.svg.expand(60 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [[
            'number', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['unavailable', False, 0, 0]]

    def _make_media_style(self, svg):
        self.svg.expand(40 + self.dx + self.ex, 10 + self.ey)
        self._make_block_graphics(svg, self.svg.basic_box)
        self.docks = [[
            'number', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['unavailable', False, 0, 0]]

    def _make_number_style(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        """
        NOTE: The "outie" is added last, so the dock order in NUMBER_STYLE
              blocks needs to be modified.
        """
        self.docks = [
            ['number', True, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['number', False, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]]
        ]

    def _make_number_style_var_arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        innie = [True]
        for i in range(self._ei + 1):
            innie.append(True)
        self.svg.set_innie(innie)
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'number', True, self.svg.docks[2 + self._ei][0],
            self.svg.docks[2 + self._ei][1]
        ], ['number', False, self.svg.docks[0][0], self.svg.docks[0][1]]]
        for i in range(self._ei + 1):
            self.docks.append([
                'number', False, self.svg.docks[i + 1][0],
                self.svg.docks[i + 1][1]
            ])
        self.docks.append(['unavailable', False, 0, 0])

    def _make_number_style_block(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['number', True, self.svg.docks[2][0], self.svg.docks[2][1], '('],
            ['number', False, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['unavailable', False, 0, 0, ')']
        ]

    def _make_number_style_1arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'number', True, self.svg.docks[1][0], self.svg.docks[1][1]
        ], ['number', False, self.svg.docks[0][0], self.svg.docks[0][1]]]

    def _make_number_style_1strarg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [[
            'number', True, self.svg.docks[1][0], self.svg.docks[1][1]
        ], ['string', False, self.svg.docks[0][0], self.svg.docks[0][1]],
                      ['unavailable', False, 0, 0]]

    def _make_number_style_porch(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_innie([True, True])
        self.svg.set_outie(True)
        self.svg.set_tab(False)
        self.svg.set_slot(False)
        self.svg.set_porch(True)
        self._make_block_graphics(svg, self.svg.basic_block)
        self.docks = [
            ['number', True, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['number', False, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]]
        ]

    def _make_compare_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_compare)
        self.docks = [
            ['bool', True, self.svg.docks[0][0], self.svg.docks[0][1], '('],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['number', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['unavailable', False, 0, 0, ')']
        ]

    def _make_compare_porch_style(self, svg):
        self.svg.set_porch(True)
        self._make_compare_style(svg)

    def _make_boolean_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_and_or)
        self.docks = [
            ['bool', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['bool', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['bool', False, self.svg.docks[2][0], self.svg.docks[2][1]]
        ]

    def _make_not_style(self, svg):
        self.svg.expand(15 + self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.boolean_not)
        self.docks = [[
            'bool', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['bool', False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_flow_style(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1], '['],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1], ']']
        ]

    def _make_flow_style_tail(self, svg):
        self.svg.expand(10 + self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(False)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_flow_style_1arg(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True])
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1], '['],
            ['flow', False, self.svg.docks[3][0], self.svg.docks[3][1], ']']
        ]

    def _make_flow_style_boolean(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_boolean(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['bool', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1], '['],
            ['flow', False, self.svg.docks[3][0], self.svg.docks[3][1], ']']
        ]

    def _make_flow_style_else(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_else(True)
        self.svg.set_boolean(True)
        self._make_block_graphics(svg, self.svg.basic_flow)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['bool', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['flow', False, self.svg.docks[3][0], self.svg.docks[3][1], '['],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1], ']['],
            ['flow', False, self.svg.docks[4][0], self.svg.docks[4][1], ']']
        ]

    def _make_collapsible_style_top(self, svg, arm=True, label=True):
        self.svg.expand(self.dx + self.ex, self.ey)
        self.svg.set_arm(arm)
        self.svg.set_show(not arm)
        self._make_block_graphics(svg, self.svg.sandwich_top, label)
        if label:
            self.docks = [
                ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
                ['number', False, self.svg.docks[1][0], self.svg.docks[1][1]],
                ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1]]
            ]
        else:
            self.docks = [[
                'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
            ], ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_collapsible_style_bottom(self, svg):
        self.svg.expand(self.dx + self.ex, self.ey)
        self._make_block_graphics(svg, self.svg.sandwich_bottom)
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]]

    def _make_invisible_style(self, svg):
        self._make_block_graphics(svg, self.svg.invisible)
        # force dock positions to be the same
        self.docks = [[
            'flow', True, self.svg.docks[0][0], self.svg.docks[0][1]
        ], ['flow', False, self.svg.docks[0][0], self.svg.docks[0][1]]]

    # Depreciated block styles

    def _make_portfolio_style_2x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['string', False, self.svg.docks[6][0], self.svg.docks[6][1]],
            ['media', False, self.svg.docks[5][0], self.svg.docks[5][1]],
            ['media', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['media', False, self.svg.docks[4][0], self.svg.docks[4][1]],
            ['media', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['flow', False, self.svg.docks[3][0], self.svg.docks[3][1]]
        ]

    def _make_portfolio_style_2x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 10 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['string', False, self.svg.docks[4][0], self.svg.docks[4][1]],
            ['media', False, self.svg.docks[3][0], self.svg.docks[3][1]],
            ['media', False, self.svg.docks[1][0], self.svg.docks[1][1]],
            ['flow', False, self.svg.docks[2][0], self.svg.docks[2][1]]
        ]

    def _make_portfolio_style_1x2(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True, False, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['string', False, self.svg.docks[4][0], self.svg.docks[4][1]],
            ['media', False, self.svg.docks[3][0], self.svg.docks[3][1]],
            ['media', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]
        ]

    def _make_portfolio_style_1x1(self, svg):
        self.svg.expand(30 + self.dx + self.ex, 15 + self.ey)
        self.svg.set_slot(True)
        self.svg.set_tab(True)
        self.svg.set_innie([True, True])
        self.svg.set_draw_innies(False)
        self._make_block_graphics(svg, self.svg.portfolio)
        self.docks = [
            ['flow', True, self.svg.docks[0][0], self.svg.docks[0][1]],
            ['string', False, self.svg.docks[3][0], self.svg.docks[3][1]],
            ['media', False, self.svg.docks[2][0], self.svg.docks[2][1]],
            ['flow', False, self.svg.docks[1][0], self.svg.docks[1][1]]
        ]

    def _make_block_graphics(self, svg, function, arg=None):
        self._set_colors(svg)
        self.svg.set_gradient(True, GRADIENT_COLOR)
        if arg is None:
            self.shapes[0] = svg_str_to_pixbuf(function())
        else:
            self.shapes[0] = svg_str_to_pixbuf(function(arg))
        self.width = self.svg.get_width()
        self.height = self.svg.get_height()
        self.svg.set_gradient(False)
        if arg is None:
            self.shapes[1] = svg_str_to_pixbuf(function())
        else:
            self.shapes[1] = svg_str_to_pixbuf(function(arg))