110259SAndrew.Bardsley@arm.com# Copyright (c) 2013 ARM Limited
210259SAndrew.Bardsley@arm.com# All rights reserved
310259SAndrew.Bardsley@arm.com#
410259SAndrew.Bardsley@arm.com# The license below extends only to copyright in the software and shall
510259SAndrew.Bardsley@arm.com# not be construed as granting a license to any other intellectual
610259SAndrew.Bardsley@arm.com# property including but not limited to intellectual property relating
710259SAndrew.Bardsley@arm.com# to a hardware implementation of the functionality of the software
810259SAndrew.Bardsley@arm.com# licensed hereunder.  You may use the software subject to the license
910259SAndrew.Bardsley@arm.com# terms below provided that you ensure that this notice is replicated
1010259SAndrew.Bardsley@arm.com# unmodified and in its entirety in all distributions of the software,
1110259SAndrew.Bardsley@arm.com# modified or unmodified, in source code or in binary form.
1210259SAndrew.Bardsley@arm.com#
1310259SAndrew.Bardsley@arm.com# Redistribution and use in source and binary forms, with or without
1410259SAndrew.Bardsley@arm.com# modification, are permitted provided that the following conditions are
1510259SAndrew.Bardsley@arm.com# met: redistributions of source code must retain the above copyright
1610259SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer;
1710259SAndrew.Bardsley@arm.com# redistributions in binary form must reproduce the above copyright
1810259SAndrew.Bardsley@arm.com# notice, this list of conditions and the following disclaimer in the
1910259SAndrew.Bardsley@arm.com# documentation and/or other materials provided with the distribution;
2010259SAndrew.Bardsley@arm.com# neither the name of the copyright holders nor the names of its
2110259SAndrew.Bardsley@arm.com# contributors may be used to endorse or promote products derived from
2210259SAndrew.Bardsley@arm.com# this software without specific prior written permission.
2310259SAndrew.Bardsley@arm.com#
2410259SAndrew.Bardsley@arm.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2510259SAndrew.Bardsley@arm.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2610259SAndrew.Bardsley@arm.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2710259SAndrew.Bardsley@arm.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2810259SAndrew.Bardsley@arm.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2910259SAndrew.Bardsley@arm.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3010259SAndrew.Bardsley@arm.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3110259SAndrew.Bardsley@arm.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3210259SAndrew.Bardsley@arm.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3310259SAndrew.Bardsley@arm.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3410259SAndrew.Bardsley@arm.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3510259SAndrew.Bardsley@arm.com#
3610259SAndrew.Bardsley@arm.com# Authors: Andrew Bardsley
3710259SAndrew.Bardsley@arm.com#
3810259SAndrew.Bardsley@arm.com# blobs.py: Blobs are the visual blocks, arrows and other coloured
3910259SAndrew.Bardsley@arm.com#   objects on the visualiser.  This file contains Blob definition and
4010259SAndrew.Bardsley@arm.com#   their rendering instructions in pygtk/cairo.
4110259SAndrew.Bardsley@arm.com#
4210259SAndrew.Bardsley@arm.com
4310259SAndrew.Bardsley@arm.comimport pygtk
4410259SAndrew.Bardsley@arm.compygtk.require('2.0')
4510259SAndrew.Bardsley@arm.comimport gtk
4610259SAndrew.Bardsley@arm.comimport gobject
4710259SAndrew.Bardsley@arm.comimport cairo
4810259SAndrew.Bardsley@arm.comimport re
4910259SAndrew.Bardsley@arm.comimport math
5010259SAndrew.Bardsley@arm.com
5110259SAndrew.Bardsley@arm.comfrom point import Point
5210259SAndrew.Bardsley@arm.comimport parse
5310259SAndrew.Bardsley@arm.comimport colours
5410259SAndrew.Bardsley@arm.comfrom colours import backgroundColour, black
5510259SAndrew.Bardsley@arm.comimport model
5610259SAndrew.Bardsley@arm.com
5710259SAndrew.Bardsley@arm.comdef centre_size_to_sides(centre, size):
5810259SAndrew.Bardsley@arm.com    """Returns a 4-tuple of the relevant ordinates of the left,
5910259SAndrew.Bardsley@arm.com    right, top and bottom sides of the described rectangle"""
6010259SAndrew.Bardsley@arm.com    (x, y) = centre.to_pair()
6110259SAndrew.Bardsley@arm.com    (half_width, half_height) = (size.scale(0.5)).to_pair()
6210259SAndrew.Bardsley@arm.com    left = x - half_width
6310259SAndrew.Bardsley@arm.com    right = x + half_width
6410259SAndrew.Bardsley@arm.com    top = y - half_height
6510259SAndrew.Bardsley@arm.com    bottom = y + half_height
6610259SAndrew.Bardsley@arm.com    return (left, right, top, bottom)
6710259SAndrew.Bardsley@arm.com
6810259SAndrew.Bardsley@arm.comdef box(cr, centre, size):
6910259SAndrew.Bardsley@arm.com    """Draw a simple box"""
7010259SAndrew.Bardsley@arm.com    (left, right, top, bottom) = centre_size_to_sides(centre, size)
7110259SAndrew.Bardsley@arm.com    cr.move_to(left, top)
7210259SAndrew.Bardsley@arm.com    cr.line_to(right, top)
7310259SAndrew.Bardsley@arm.com    cr.line_to(right, bottom)
7410259SAndrew.Bardsley@arm.com    cr.line_to(left, bottom)
7510259SAndrew.Bardsley@arm.com    cr.close_path()
7610259SAndrew.Bardsley@arm.com
7710259SAndrew.Bardsley@arm.comdef stroke_and_fill(cr, colour):
7810259SAndrew.Bardsley@arm.com    """Stroke with the current colour then fill the same path with the
7910259SAndrew.Bardsley@arm.com    given colour"""
8010259SAndrew.Bardsley@arm.com    join = cr.get_line_join()
8110259SAndrew.Bardsley@arm.com    cr.set_line_join(gtk.gdk.JOIN_ROUND)
8210259SAndrew.Bardsley@arm.com    cr.close_path()
8310259SAndrew.Bardsley@arm.com    cr.set_source_color(backgroundColour)
8410259SAndrew.Bardsley@arm.com    cr.stroke_preserve()
8510259SAndrew.Bardsley@arm.com    cr.set_source_color(colour)
8610259SAndrew.Bardsley@arm.com    cr.fill()
8710259SAndrew.Bardsley@arm.com    cr.set_line_join(join)
8810259SAndrew.Bardsley@arm.com
8910259SAndrew.Bardsley@arm.comdef striped_box(cr, centre, size, colours):
9010259SAndrew.Bardsley@arm.com    """Fill a rectangle (without outline) striped with the colours given"""
9110259SAndrew.Bardsley@arm.com    num_colours = len(colours)
9210259SAndrew.Bardsley@arm.com    if num_colours == 0:
9310259SAndrew.Bardsley@arm.com        box(cr, centre, size)
9410259SAndrew.Bardsley@arm.com        cr.set_source_color(backgroundColour)
9510259SAndrew.Bardsley@arm.com        cr.fill()
9610259SAndrew.Bardsley@arm.com    elif num_colours == 1:
9710259SAndrew.Bardsley@arm.com        box(cr, centre, size)
9810259SAndrew.Bardsley@arm.com        stroke_and_fill(cr, colours[0])
9910259SAndrew.Bardsley@arm.com    else:
10010259SAndrew.Bardsley@arm.com        (left, right, top, bottom) = centre_size_to_sides(centre, size)
10110259SAndrew.Bardsley@arm.com        (width, height) = size.to_pair()
10210259SAndrew.Bardsley@arm.com        x_stripe_width = width / num_colours
10310259SAndrew.Bardsley@arm.com        half_x_stripe_width = x_stripe_width / 2.0
10410259SAndrew.Bardsley@arm.com        # Left triangle
10510259SAndrew.Bardsley@arm.com        cr.move_to(left,  bottom)
10610259SAndrew.Bardsley@arm.com        cr.line_to(left + half_x_stripe_width, bottom)
10710259SAndrew.Bardsley@arm.com        cr.line_to(left + x_stripe_width + half_x_stripe_width, top)
10810259SAndrew.Bardsley@arm.com        cr.line_to(left, top)
10910259SAndrew.Bardsley@arm.com        stroke_and_fill(cr, colours[0])
11010259SAndrew.Bardsley@arm.com        # Stripes
11110259SAndrew.Bardsley@arm.com        for i in xrange(1, num_colours - 1):
11210259SAndrew.Bardsley@arm.com            xOffset = x_stripe_width * i
11310259SAndrew.Bardsley@arm.com            cr.move_to(left + xOffset - half_x_stripe_width, bottom)
11410259SAndrew.Bardsley@arm.com            cr.line_to(left + xOffset + half_x_stripe_width, bottom)
11510259SAndrew.Bardsley@arm.com            cr.line_to(left + xOffset + x_stripe_width +
11610259SAndrew.Bardsley@arm.com                half_x_stripe_width, top)
11710259SAndrew.Bardsley@arm.com            cr.line_to(left + xOffset + x_stripe_width -
11810259SAndrew.Bardsley@arm.com                half_x_stripe_width, top)
11910259SAndrew.Bardsley@arm.com            stroke_and_fill(cr, colours[i])
12010259SAndrew.Bardsley@arm.com        # Right triangle
12110259SAndrew.Bardsley@arm.com        cr.move_to((right - x_stripe_width) - half_x_stripe_width, bottom)
12210259SAndrew.Bardsley@arm.com        cr.line_to(right, bottom)
12310259SAndrew.Bardsley@arm.com        cr.line_to(right, top)
12410259SAndrew.Bardsley@arm.com        cr.line_to((right - x_stripe_width) + half_x_stripe_width, top)
12510259SAndrew.Bardsley@arm.com        stroke_and_fill(cr, colours[num_colours - 1])
12610259SAndrew.Bardsley@arm.com
12710259SAndrew.Bardsley@arm.comdef speech_bubble(cr, top_left, size, unit):
12810259SAndrew.Bardsley@arm.com    """Draw a speech bubble with 'size'-sized internal space with its
12910259SAndrew.Bardsley@arm.com    top left corner at Point(2.0 * unit, 2.0 * unit)"""
13010259SAndrew.Bardsley@arm.com    def local_arc(centre, angleFrom, angleTo):
13110259SAndrew.Bardsley@arm.com        cr.arc(centre.x, centre.y, unit, angleFrom * math.pi,
13210259SAndrew.Bardsley@arm.com            angleTo * math.pi)
13310259SAndrew.Bardsley@arm.com
13410259SAndrew.Bardsley@arm.com    cr.move_to(*top_left.to_pair())
13510259SAndrew.Bardsley@arm.com    cr.rel_line_to(unit * 2.0, unit)
13610259SAndrew.Bardsley@arm.com    cr.rel_line_to(size.x, 0.0)
13710259SAndrew.Bardsley@arm.com    local_arc(top_left + Point(size.x + unit * 2.0, unit * 2.0), -0.5, 0.0)
13810259SAndrew.Bardsley@arm.com    cr.rel_line_to(0.0, size.y)
13910259SAndrew.Bardsley@arm.com    local_arc(top_left + Point(size.x + unit * 2.0, size.y + unit * 2.0),
14010259SAndrew.Bardsley@arm.com        0, 0.5)
14110259SAndrew.Bardsley@arm.com    cr.rel_line_to(-size.x, 0.0)
14210259SAndrew.Bardsley@arm.com    local_arc(top_left + Point(unit * 2.0, size.y + unit * 2.0), 0.5, 1.0)
14310259SAndrew.Bardsley@arm.com    cr.rel_line_to(0, -size.y)
14410259SAndrew.Bardsley@arm.com    cr.close_path()
14510259SAndrew.Bardsley@arm.com
14610259SAndrew.Bardsley@arm.comdef open_bottom(cr, centre, size):
14710259SAndrew.Bardsley@arm.com    """Draw a box with left, top and right sides"""
14810259SAndrew.Bardsley@arm.com    (left, right, top, bottom) = centre_size_to_sides(centre, size)
14910259SAndrew.Bardsley@arm.com    cr.move_to(left, bottom)
15010259SAndrew.Bardsley@arm.com    cr.line_to(left, top)
15110259SAndrew.Bardsley@arm.com    cr.line_to(right, top)
15210259SAndrew.Bardsley@arm.com    cr.line_to(right, bottom)
15310259SAndrew.Bardsley@arm.com
15410259SAndrew.Bardsley@arm.comdef fifo(cr, centre, size):
15510259SAndrew.Bardsley@arm.com    """Draw just the vertical sides of a box"""
15610259SAndrew.Bardsley@arm.com    (left, right, top, bottom) = centre_size_to_sides(centre, size)
15710259SAndrew.Bardsley@arm.com    cr.move_to(left, bottom)
15810259SAndrew.Bardsley@arm.com    cr.line_to(left, top)
15910259SAndrew.Bardsley@arm.com    cr.move_to(right, bottom)
16010259SAndrew.Bardsley@arm.com    cr.line_to(right, top)
16110259SAndrew.Bardsley@arm.com
16210259SAndrew.Bardsley@arm.comdef cross(cr, centre, size):
16310259SAndrew.Bardsley@arm.com    """Draw a cross parallel with the axes"""
16410259SAndrew.Bardsley@arm.com    (left, right, top, bottom) = centre_size_to_sides(centre, size)
16510259SAndrew.Bardsley@arm.com    (x, y) = centre.to_pair()
16610259SAndrew.Bardsley@arm.com    cr.move_to(left, y)
16710259SAndrew.Bardsley@arm.com    cr.line_to(right, y)
16810259SAndrew.Bardsley@arm.com    cr.move_to(x, top)
16910259SAndrew.Bardsley@arm.com    cr.line_to(x, bottom)
17010259SAndrew.Bardsley@arm.com
17110259SAndrew.Bardsley@arm.comclass Blob(object):
17210259SAndrew.Bardsley@arm.com    """Blob super class"""
17310259SAndrew.Bardsley@arm.com    def __init__(self, picChar, unit, topLeft, colour, size = Point(1,1)):
17410259SAndrew.Bardsley@arm.com        self.picChar = picChar
17510259SAndrew.Bardsley@arm.com        self.unit = unit
17610259SAndrew.Bardsley@arm.com        self.displayName = unit
17710259SAndrew.Bardsley@arm.com        self.nameLoc = 'top'
17810259SAndrew.Bardsley@arm.com        self.topLeft = topLeft
17910259SAndrew.Bardsley@arm.com        self.colour = colour
18010259SAndrew.Bardsley@arm.com        self.size = size
18110259SAndrew.Bardsley@arm.com        self.border = 1.0
18210259SAndrew.Bardsley@arm.com        self.dataSelect = model.BlobDataSelect()
18310259SAndrew.Bardsley@arm.com        self.shorten = 0
18410259SAndrew.Bardsley@arm.com
18510259SAndrew.Bardsley@arm.com    def render(self, cr, view, event, select, time):
18610259SAndrew.Bardsley@arm.com        """Render this blob with the given event's data.  Returns either
18710259SAndrew.Bardsley@arm.com        None or a pair of (centre, size) in device coordinates for the drawn
18810259SAndrew.Bardsley@arm.com        blob.  The return value can be used to detect if mouse clicks on
18910259SAndrew.Bardsley@arm.com        the canvas are within the blob"""
19010259SAndrew.Bardsley@arm.com        return None
19110259SAndrew.Bardsley@arm.com
19210259SAndrew.Bardsley@arm.comclass Block(Blob):
19310259SAndrew.Bardsley@arm.com    """Blocks are rectangular blogs colourable with a 2D grid of striped
19410259SAndrew.Bardsley@arm.com    blocks.  visualDecoder specifies how event data becomes this coloured
19510259SAndrew.Bardsley@arm.com    grid"""
19610259SAndrew.Bardsley@arm.com    def __init__(self, picChar, unit, topLeft=Point(0,0),
19710259SAndrew.Bardsley@arm.com        colour=colours.black,
19810259SAndrew.Bardsley@arm.com        size=Point(1,1)):
19910259SAndrew.Bardsley@arm.com        super(Block,self).__init__(picChar, unit, topLeft, colour,
20010259SAndrew.Bardsley@arm.com            size = size)
20110259SAndrew.Bardsley@arm.com        # {horiz, vert}
20210259SAndrew.Bardsley@arm.com        self.stripDir = 'horiz'
20310259SAndrew.Bardsley@arm.com        # {LR, RL}: LR means the first strip will be on the left/top,
20410259SAndrew.Bardsley@arm.com        #   RL means the first strip will be on the right/bottom
20510259SAndrew.Bardsley@arm.com        self.stripOrd = 'LR'
20610259SAndrew.Bardsley@arm.com        # Number of blank strips if this is a frame
20710259SAndrew.Bardsley@arm.com        self.blankStrips = 0
20810259SAndrew.Bardsley@arm.com        # {box, fifo, openBottom}
20910259SAndrew.Bardsley@arm.com        self.shape = 'box'
21010259SAndrew.Bardsley@arm.com        self.visualDecoder = None
21110259SAndrew.Bardsley@arm.com
21210259SAndrew.Bardsley@arm.com    def render(self, cr, view, event, select, time):
21310259SAndrew.Bardsley@arm.com        # Find the right event, visuals and sizes for things
21410259SAndrew.Bardsley@arm.com        if event is None or self.displayName.startswith('_'):
21510259SAndrew.Bardsley@arm.com            event = model.BlobEvent(self.unit, time)
21610259SAndrew.Bardsley@arm.com
21710259SAndrew.Bardsley@arm.com        if self.picChar in event.visuals:
21810259SAndrew.Bardsley@arm.com            strips = event.visuals[self.picChar].to_striped_block(
21910259SAndrew.Bardsley@arm.com                select & self.dataSelect)
22010259SAndrew.Bardsley@arm.com        else:
22110259SAndrew.Bardsley@arm.com            strips = [[[colours.unknownColour]]]
22210259SAndrew.Bardsley@arm.com
22310259SAndrew.Bardsley@arm.com        if self.stripOrd == 'RL':
22410259SAndrew.Bardsley@arm.com            strips.reverse()
22510259SAndrew.Bardsley@arm.com
22610259SAndrew.Bardsley@arm.com        if len(strips) == 0:
22710259SAndrew.Bardsley@arm.com            strips = [[colours.errorColour]]
22810259SAndrew.Bardsley@arm.com            print 'Problem with the colour of event:', event
22910259SAndrew.Bardsley@arm.com
23010259SAndrew.Bardsley@arm.com        num_strips = len(strips)
23110259SAndrew.Bardsley@arm.com        strip_proportion = 1.0 / num_strips
23210259SAndrew.Bardsley@arm.com        first_strip_offset = (num_strips / 2.0) - 0.5
23310259SAndrew.Bardsley@arm.com
23410259SAndrew.Bardsley@arm.com        # Adjust blocks with 'shorten' attribute to the length of the data
23510259SAndrew.Bardsley@arm.com        size = Point(*self.size.to_pair())
23610259SAndrew.Bardsley@arm.com        if self.shorten != 0 and self.size.x > (num_strips * self.shorten):
23710259SAndrew.Bardsley@arm.com            size.x = num_strips * self.shorten
23810259SAndrew.Bardsley@arm.com
23910259SAndrew.Bardsley@arm.com        box_size = size - view.blobIndentFactor.scale(2)
24010259SAndrew.Bardsley@arm.com
24110259SAndrew.Bardsley@arm.com        # Now do cr sensitive things
24210259SAndrew.Bardsley@arm.com        cr.save()
24310259SAndrew.Bardsley@arm.com        cr.scale(*view.pitch.to_pair())
24410259SAndrew.Bardsley@arm.com        cr.translate(*self.topLeft.to_pair())
24510259SAndrew.Bardsley@arm.com        cr.translate(*(size - Point(1,1)).scale(0.5).to_pair())
24610259SAndrew.Bardsley@arm.com
24710259SAndrew.Bardsley@arm.com        translated_centre = Point(*cr.user_to_device(0.0, 0.0))
24810259SAndrew.Bardsley@arm.com        translated_size = \
24910259SAndrew.Bardsley@arm.com            Point(*cr.user_to_device_distance(*size.to_pair()))
25010259SAndrew.Bardsley@arm.com
25110259SAndrew.Bardsley@arm.com        # The 2D grid is a grid of strips of blocks.  Data [[1,2],[3]]
25210259SAndrew.Bardsley@arm.com        # is 2 strips of 2 and 1 blocks respectively.
25310259SAndrew.Bardsley@arm.com        # if stripDir == 'horiz', strips are stacked vertically
25410259SAndrew.Bardsley@arm.com        #   from top to bottom if stripOrd == 'LR' or bottom to top if
25510259SAndrew.Bardsley@arm.com        #   stripOrd == 'RL'.
25610259SAndrew.Bardsley@arm.com        # if stripDir == 'vert', strips are stacked horizontally
25710259SAndrew.Bardsley@arm.com        #   from left to right if stripOf == 'LR' or right to left if
25810259SAndrew.Bardsley@arm.com        #   stripOrd == 'RL'.
25910259SAndrew.Bardsley@arm.com
26010259SAndrew.Bardsley@arm.com        strip_is_horiz = self.stripDir == 'horiz'
26110259SAndrew.Bardsley@arm.com
26210259SAndrew.Bardsley@arm.com        if strip_is_horiz:
26310259SAndrew.Bardsley@arm.com            strip_step_base = Point(1.0,0.0)
26410259SAndrew.Bardsley@arm.com            block_step_base = Point(0.0,1.0)
26510259SAndrew.Bardsley@arm.com        else:
26610259SAndrew.Bardsley@arm.com            strip_step_base = Point(0.0,1.0)
26710259SAndrew.Bardsley@arm.com            block_step_base = Point(1.0,0.0)
26810259SAndrew.Bardsley@arm.com
26910259SAndrew.Bardsley@arm.com        strip_size = (box_size * (strip_step_base.scale(strip_proportion) +
27010259SAndrew.Bardsley@arm.com            block_step_base))
27110259SAndrew.Bardsley@arm.com        strip_step = strip_size * strip_step_base
27210259SAndrew.Bardsley@arm.com        strip_centre = Point(0,0) - (strip_size *
27310259SAndrew.Bardsley@arm.com            strip_step_base.scale(first_strip_offset))
27410259SAndrew.Bardsley@arm.com
27510259SAndrew.Bardsley@arm.com        cr.set_line_width(view.midLineWidth / view.pitch.x)
27610259SAndrew.Bardsley@arm.com
27710259SAndrew.Bardsley@arm.com        # Draw the strips and their blocks
27810259SAndrew.Bardsley@arm.com        for strip_index in xrange(0, num_strips):
27910259SAndrew.Bardsley@arm.com            num_blocks = len(strips[strip_index])
28010259SAndrew.Bardsley@arm.com            block_proportion = 1.0 / num_blocks
28110259SAndrew.Bardsley@arm.com            firstBlockOffset = (num_blocks / 2.0) - 0.5
28210259SAndrew.Bardsley@arm.com
28310259SAndrew.Bardsley@arm.com            block_size = (strip_size *
28410259SAndrew.Bardsley@arm.com                (block_step_base.scale(block_proportion) +
28510259SAndrew.Bardsley@arm.com                strip_step_base))
28610259SAndrew.Bardsley@arm.com            block_step = block_size * block_step_base
28710259SAndrew.Bardsley@arm.com            block_centre = (strip_centre + strip_step.scale(strip_index) -
28810259SAndrew.Bardsley@arm.com                (block_size * block_step_base.scale(firstBlockOffset)))
28910259SAndrew.Bardsley@arm.com
29010259SAndrew.Bardsley@arm.com            for block_index in xrange(0, num_blocks):
29110259SAndrew.Bardsley@arm.com                striped_box(cr, block_centre +
29210259SAndrew.Bardsley@arm.com                    block_step.scale(block_index), block_size,
29310259SAndrew.Bardsley@arm.com                    strips[strip_index][block_index])
29410259SAndrew.Bardsley@arm.com
29510259SAndrew.Bardsley@arm.com        cr.set_font_size(0.7)
29610259SAndrew.Bardsley@arm.com        if self.border > 0.5:
29710259SAndrew.Bardsley@arm.com            weight = cairo.FONT_WEIGHT_BOLD
29810259SAndrew.Bardsley@arm.com        else:
29910259SAndrew.Bardsley@arm.com            weight = cairo.FONT_WEIGHT_NORMAL
30010259SAndrew.Bardsley@arm.com        cr.select_font_face('Helvetica', cairo.FONT_SLANT_NORMAL,
30110259SAndrew.Bardsley@arm.com            weight)
30210259SAndrew.Bardsley@arm.com
30310259SAndrew.Bardsley@arm.com        xb, yb, width, height, dx, dy = cr.text_extents(self.displayName)
30410259SAndrew.Bardsley@arm.com
30510259SAndrew.Bardsley@arm.com        text_comfort_space = 0.15
30610259SAndrew.Bardsley@arm.com
30710259SAndrew.Bardsley@arm.com        if self.nameLoc == 'left':
30810259SAndrew.Bardsley@arm.com            # Position text vertically along left side, top aligned
30910259SAndrew.Bardsley@arm.com            cr.save()
31010259SAndrew.Bardsley@arm.com            cr.rotate(- (math.pi / 2.0))
31110259SAndrew.Bardsley@arm.com            text_point = Point(size.y, size.x).scale(0.5) * Point(-1, -1)
31210259SAndrew.Bardsley@arm.com            text_point += Point(max(0, size.y - width), 0)
31310259SAndrew.Bardsley@arm.com            text_point += Point(-text_comfort_space, -text_comfort_space)
31410259SAndrew.Bardsley@arm.com        else: # Including top
31510259SAndrew.Bardsley@arm.com            # Position text above the top left hand corner
31610259SAndrew.Bardsley@arm.com            text_point = size.scale(0.5) * Point(-1,-1)
31710259SAndrew.Bardsley@arm.com            text_point += Point(0.00, -text_comfort_space)
31810259SAndrew.Bardsley@arm.com
31910259SAndrew.Bardsley@arm.com        if (self.displayName != '' and
32010259SAndrew.Bardsley@arm.com            not self.displayName.startswith('_')):
32110259SAndrew.Bardsley@arm.com            cr.set_source_color(self.colour)
32210259SAndrew.Bardsley@arm.com            cr.move_to(*text_point.to_pair())
32310259SAndrew.Bardsley@arm.com            cr.show_text(self.displayName)
32410259SAndrew.Bardsley@arm.com
32510259SAndrew.Bardsley@arm.com        if self.nameLoc == 'left':
32610259SAndrew.Bardsley@arm.com            cr.restore()
32710259SAndrew.Bardsley@arm.com
32810259SAndrew.Bardsley@arm.com        # Draw the outline shape
32910259SAndrew.Bardsley@arm.com        cr.save()
33010259SAndrew.Bardsley@arm.com        if strip_is_horiz:
33110259SAndrew.Bardsley@arm.com            cr.rotate(- (math.pi / 2.0))
33210259SAndrew.Bardsley@arm.com            box_size = Point(box_size.y, box_size.x)
33310259SAndrew.Bardsley@arm.com
33410259SAndrew.Bardsley@arm.com        if self.stripOrd == "RL":
33510259SAndrew.Bardsley@arm.com            cr.rotate(math.pi)
33610259SAndrew.Bardsley@arm.com
33710259SAndrew.Bardsley@arm.com        if self.shape == 'box':
33810259SAndrew.Bardsley@arm.com            box(cr, Point(0,0), box_size)
33910259SAndrew.Bardsley@arm.com        elif self.shape == 'openBottom':
34010259SAndrew.Bardsley@arm.com            open_bottom(cr, Point(0,0), box_size)
34110259SAndrew.Bardsley@arm.com        elif self.shape == 'fifo':
34210259SAndrew.Bardsley@arm.com            fifo(cr, Point(0,0), box_size)
34310259SAndrew.Bardsley@arm.com        cr.restore()
34410259SAndrew.Bardsley@arm.com
34510259SAndrew.Bardsley@arm.com        # Restore scale and stroke the outline
34610259SAndrew.Bardsley@arm.com        cr.restore()
34710259SAndrew.Bardsley@arm.com        cr.set_source_color(self.colour)
34810259SAndrew.Bardsley@arm.com        cr.set_line_width(view.thickLineWidth * self.border)
34910259SAndrew.Bardsley@arm.com        cr.stroke()
35010259SAndrew.Bardsley@arm.com
35110259SAndrew.Bardsley@arm.com        # Return blob size/position
35210259SAndrew.Bardsley@arm.com        if self.unit == '_':
35310259SAndrew.Bardsley@arm.com            return None
35410259SAndrew.Bardsley@arm.com        else:
35510259SAndrew.Bardsley@arm.com            return (translated_centre, translated_size)
35610259SAndrew.Bardsley@arm.com
35710259SAndrew.Bardsley@arm.comclass Key(Blob):
35810259SAndrew.Bardsley@arm.com    """Draw a key to the special (and numeric colours) with swatches of the
35910259SAndrew.Bardsley@arm.com    colours half as wide as the key"""
36010259SAndrew.Bardsley@arm.com    def __init__(self, picChar, unit, topLeft, colour=colours.black,
36110259SAndrew.Bardsley@arm.com        size=Point(1,1)):
36210259SAndrew.Bardsley@arm.com        super(Key,self).__init__(picChar, unit, topLeft, colour, size = size)
36310259SAndrew.Bardsley@arm.com        self.colours = 'BBBB'
36410259SAndrew.Bardsley@arm.com        self.displayName = unit
36510259SAndrew.Bardsley@arm.com
36610259SAndrew.Bardsley@arm.com    def render(self, cr, view, event, select, time):
36710259SAndrew.Bardsley@arm.com        cr.save()
36810259SAndrew.Bardsley@arm.com        cr.scale(*view.pitch.to_pair())
36910259SAndrew.Bardsley@arm.com        cr.translate(*self.topLeft.to_pair())
37010259SAndrew.Bardsley@arm.com        # cr.translate(*(self.size - Point(1,1)).scale(0.5).to_pair())
37110259SAndrew.Bardsley@arm.com        half_width = self.size.x / 2.0
37210259SAndrew.Bardsley@arm.com        cr.translate(*(self.size - Point(1.0 + half_width,1.0)).scale(0.5).
37310259SAndrew.Bardsley@arm.com            to_pair())
37410259SAndrew.Bardsley@arm.com
37510259SAndrew.Bardsley@arm.com        num_colours = len(self.colours)
37610259SAndrew.Bardsley@arm.com        cr.set_line_width(view.midLineWidth / view.pitch.x)
37710259SAndrew.Bardsley@arm.com
37810259SAndrew.Bardsley@arm.com        blob_size = (Point(half_width,0.0) +
37910259SAndrew.Bardsley@arm.com            (self.size * Point(0.0,1.0 / num_colours)))
38010259SAndrew.Bardsley@arm.com        blob_step = Point(0.0,1.0) * blob_size
38110259SAndrew.Bardsley@arm.com        first_blob_centre = (Point(0.0,0.0) -
38210259SAndrew.Bardsley@arm.com            blob_step.scale((num_colours / 2.0) - 0.5))
38310259SAndrew.Bardsley@arm.com
38410259SAndrew.Bardsley@arm.com        cr.set_source_color(self.colour)
38510259SAndrew.Bardsley@arm.com        cr.set_line_width(view.thinLineWidth / view.pitch.x)
38610259SAndrew.Bardsley@arm.com
38710259SAndrew.Bardsley@arm.com        blob_proportion = 0.8
38810259SAndrew.Bardsley@arm.com
38910259SAndrew.Bardsley@arm.com        real_blob_size = blob_size.scale(blob_proportion)
39010259SAndrew.Bardsley@arm.com
39110259SAndrew.Bardsley@arm.com        cr.set_font_size(0.8 * blob_size.y * blob_proportion)
39210259SAndrew.Bardsley@arm.com        cr.select_font_face('Helvetica', cairo.FONT_SLANT_NORMAL,
39310259SAndrew.Bardsley@arm.com            cairo.FONT_WEIGHT_BOLD)
39410259SAndrew.Bardsley@arm.com
39510259SAndrew.Bardsley@arm.com        for i in xrange(0, num_colours):
39610259SAndrew.Bardsley@arm.com            centre = first_blob_centre + blob_step.scale(i)
39710259SAndrew.Bardsley@arm.com            box(cr, centre, real_blob_size)
39810259SAndrew.Bardsley@arm.com
39910259SAndrew.Bardsley@arm.com            colour_char = self.colours[i]
40010259SAndrew.Bardsley@arm.com            if colour_char.isdigit():
40110259SAndrew.Bardsley@arm.com                cr.set_source_color(colours.number_to_colour(
40210259SAndrew.Bardsley@arm.com                    int(colour_char)))
40310259SAndrew.Bardsley@arm.com                label = '...' + colour_char
40410259SAndrew.Bardsley@arm.com            else:
40510259SAndrew.Bardsley@arm.com                cr.set_source_color(model.special_state_colours[colour_char])
40610259SAndrew.Bardsley@arm.com                label = model.special_state_names[colour_char]
40710259SAndrew.Bardsley@arm.com
40810259SAndrew.Bardsley@arm.com            cr.fill_preserve()
40910259SAndrew.Bardsley@arm.com            cr.set_source_color(self.colour)
41010259SAndrew.Bardsley@arm.com            cr.stroke()
41110259SAndrew.Bardsley@arm.com
41210259SAndrew.Bardsley@arm.com            xb, yb, width, height, dx, dy = cr.text_extents(label)
41310259SAndrew.Bardsley@arm.com
41410259SAndrew.Bardsley@arm.com            text_left = (centre + (Point(0.5,0.0) * blob_size) +
41510259SAndrew.Bardsley@arm.com                Point(0.0, height / 2.0))
41610259SAndrew.Bardsley@arm.com
41710259SAndrew.Bardsley@arm.com            cr.move_to(*text_left.to_pair())
41810259SAndrew.Bardsley@arm.com            cr.show_text(label)
41910259SAndrew.Bardsley@arm.com
42010259SAndrew.Bardsley@arm.comclass Arrow(Blob):
42110259SAndrew.Bardsley@arm.com    """Draw a left or right facing arrow"""
42210259SAndrew.Bardsley@arm.com    def __init__(self, unit, topLeft, colour=colours.black,
42310259SAndrew.Bardsley@arm.com        size=Point(1.0,1.0), direc='right'):
42410259SAndrew.Bardsley@arm.com        super(Arrow,self).__init__(unit, unit, topLeft, colour, size = size)
42510259SAndrew.Bardsley@arm.com        self.direc = direc
42610259SAndrew.Bardsley@arm.com
42710259SAndrew.Bardsley@arm.com    def render(self, cr, view, event, select, time):
42810259SAndrew.Bardsley@arm.com        cr.save()
42910259SAndrew.Bardsley@arm.com        cr.scale(*view.pitch.to_pair())
43010259SAndrew.Bardsley@arm.com        cr.translate(*self.topLeft.to_pair())
43110259SAndrew.Bardsley@arm.com        cr.translate(*(self.size - Point(1,1)).scale(0.5).to_pair())
43210259SAndrew.Bardsley@arm.com        cr.scale(*self.size.to_pair())
43310259SAndrew.Bardsley@arm.com        (blob_indent_x, blob_indent_y) = \
43410259SAndrew.Bardsley@arm.com            (view.blobIndentFactor / self.size).to_pair()
43510259SAndrew.Bardsley@arm.com        left = -0.5 - blob_indent_x
43610259SAndrew.Bardsley@arm.com        right = 0.5 + blob_indent_x
43710259SAndrew.Bardsley@arm.com
43810259SAndrew.Bardsley@arm.com        thickness = 0.2
43910259SAndrew.Bardsley@arm.com        flare = 0.2
44010259SAndrew.Bardsley@arm.com
44110259SAndrew.Bardsley@arm.com        if self.direc == 'left':
44210259SAndrew.Bardsley@arm.com            cr.rotate(math.pi)
44310259SAndrew.Bardsley@arm.com
44410259SAndrew.Bardsley@arm.com        cr.move_to(left, -thickness)
44510259SAndrew.Bardsley@arm.com        cr.line_to(0.0, -thickness)
44610259SAndrew.Bardsley@arm.com        cr.line_to(0.0, -(thickness + flare))
44710259SAndrew.Bardsley@arm.com        cr.line_to(right, 0)
44810259SAndrew.Bardsley@arm.com        # Break arrow to prevent the point ruining the appearance of boxes
44910259SAndrew.Bardsley@arm.com        cr.move_to(right, 0)
45010259SAndrew.Bardsley@arm.com        cr.line_to(0.0, (thickness + flare))
45110259SAndrew.Bardsley@arm.com        cr.line_to(0.0, +thickness)
45210259SAndrew.Bardsley@arm.com        cr.line_to(left, +thickness)
45310259SAndrew.Bardsley@arm.com
45410259SAndrew.Bardsley@arm.com        cr.restore()
45510259SAndrew.Bardsley@arm.com
45610259SAndrew.Bardsley@arm.com        # Draw arrow a bit more lightly than the standard line width
45710259SAndrew.Bardsley@arm.com        cr.set_line_width(cr.get_line_width() * 0.75)
45810259SAndrew.Bardsley@arm.com        cr.set_source_color(self.colour)
45910259SAndrew.Bardsley@arm.com        cr.stroke()
46010259SAndrew.Bardsley@arm.com
46110259SAndrew.Bardsley@arm.com        return None
462