/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
1 by Scott James Remnant
Commit the first version of bzrk.
1
# -*- coding: UTF-8 -*-
2
"""Cell renderer for directed graph.
3
4
This module contains the implementation of a custom GtkCellRenderer that
5
draws part of the directed graph based on the lines suggested by the code
6
in graph.py.
7
8
Because we're shiny, we use Cairo to do this, and because we're naughty
9
we cheat and draw over the bits of the TreeViewColumn that are supposed to
10
just be for the background.
11
"""
12
13
__copyright__ = "Copyright © 2005 Canonical Ltd."
14
__author__    = "Scott James Remnant <scott@ubuntu.com>"
15
16
17
import math
18
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
19
from gi.repository import Gtk
20
from gi.repository import GObject
21
from gi.repository import Pango
1 by Scott James Remnant
Commit the first version of bzrk.
22
import cairo
23
24
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
25
class CellRendererGraph(Gtk.GenericCellRenderer):
1 by Scott James Remnant
Commit the first version of bzrk.
26
    """Cell renderer for directed graph.
27
28
    Properties:
29
      node              (column, colour) tuple to draw revision node,
30
      in_lines          (start, end, colour) tuple list to draw inward lines,
31
      out_lines         (start, end, colour) tuple list to draw outward lines.
32
    """
724 by Jelmer Vernooij
Fix formatting, imports.
33
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
34
    columns_len = 0
1 by Scott James Remnant
Commit the first version of bzrk.
35
36
    __gproperties__ = {
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
37
        "node":         ( GObject.TYPE_PYOBJECT, "node",
1 by Scott James Remnant
Commit the first version of bzrk.
38
                          "revision node instruction",
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
39
                          GObject.PARAM_WRITABLE
1 by Scott James Remnant
Commit the first version of bzrk.
40
                        ),
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
41
        "tags":         ( GObject.TYPE_PYOBJECT, "tags",
423.5.1 by Ali Sabil
Added tags visualization in the graph
42
                          "list of tags associated with the node",
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
43
                          GObject.PARAM_WRITABLE
423.5.1 by Ali Sabil
Added tags visualization in the graph
44
                        ),
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
45
        "in-lines":     ( GObject.TYPE_PYOBJECT, "in-lines",
1 by Scott James Remnant
Commit the first version of bzrk.
46
                          "instructions to draw lines into the cell",
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
47
                          GObject.PARAM_WRITABLE
1 by Scott James Remnant
Commit the first version of bzrk.
48
                        ),
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
49
        "out-lines":    ( GObject.TYPE_PYOBJECT, "out-lines",
1 by Scott James Remnant
Commit the first version of bzrk.
50
                          "instructions to draw lines out of the cell",
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
51
                          GObject.PARAM_WRITABLE
1 by Scott James Remnant
Commit the first version of bzrk.
52
                        ),
53
        }
724 by Jelmer Vernooij
Fix formatting, imports.
54
1 by Scott James Remnant
Commit the first version of bzrk.
55
    def do_set_property(self, property, value):
56
        """Set properties from GObject properties."""
57
        if property.name == "node":
58
            self.node = value
423.5.1 by Ali Sabil
Added tags visualization in the graph
59
        elif property.name == "tags":
60
            self.tags = value
1 by Scott James Remnant
Commit the first version of bzrk.
61
        elif property.name == "in-lines":
62
            self.in_lines = value
63
        elif property.name == "out-lines":
64
            self.out_lines = value
65
        else:
66
            raise AttributeError, "no such property: '%s'" % property.name
67
68
    def box_size(self, widget):
69
        """Calculate box size based on widget's font.
70
71
        Cache this as it's probably expensive to get.  It ensures that we
72
        draw the graph at least as large as the text.
73
        """
74
        try:
75
            return self._box_size
76
        except AttributeError:
77
            pango_ctx = widget.get_pango_context()
78
            font_desc = widget.get_style().font_desc
79
            metrics = pango_ctx.get_metrics(font_desc)
80
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
81
            ascent = Pango.PIXELS(metrics.get_ascent())
82
            descent = Pango.PIXELS(metrics.get_descent())
1 by Scott James Remnant
Commit the first version of bzrk.
83
9 by Scott James Remnant
Fix the busted font size stuff, and then increase the sizes a bit to
84
            self._box_size = ascent + descent + 6
1 by Scott James Remnant
Commit the first version of bzrk.
85
            return self._box_size
86
87
    def set_colour(self, ctx, colour, bg, fg):
88
        """Set the context source colour.
89
90
        Picks a distinct colour based on an internal wheel; the bg
91
        parameter provides the value that should be assigned to the 'zero'
92
        colours and the fg parameter provides the multiplier that should be
93
        applied to the foreground colours.
94
        """
256.2.43 by Gary van der Merwe
Make the mainline allways black - which often makes the graph easier to read.
95
        mainline_color = ( 0.0, 0.0, 0.0 )
1 by Scott James Remnant
Commit the first version of bzrk.
96
        colours = [
97
            ( 1.0, 0.0, 0.0 ),
98
            ( 1.0, 1.0, 0.0 ),
99
            ( 0.0, 1.0, 0.0 ),
100
            ( 0.0, 1.0, 1.0 ),
101
            ( 0.0, 0.0, 1.0 ),
102
            ( 1.0, 0.0, 1.0 ),
103
            ]
104
256.2.43 by Gary van der Merwe
Make the mainline allways black - which often makes the graph easier to read.
105
        if colour == 0:
106
            colour_rgb = mainline_color
107
        else:
108
            colour_rgb = colours[colour % len(colours)]
109
110
        red   = (colour_rgb[0] * fg) or bg
111
        green = (colour_rgb[1] * fg) or bg
112
        blue  = (colour_rgb[2] * fg) or bg
1 by Scott James Remnant
Commit the first version of bzrk.
113
114
        ctx.set_source_rgb(red, green, blue)
115
116
    def on_get_size(self, widget, cell_area):
117
        """Return the size we need for this cell.
118
119
        Each cell is drawn individually and is only as wide as it needs
120
        to be, we let the TreeViewColumn take care of making them all
121
        line up.
122
        """
66.2.19 by Aaron Bentley
Increase box height by 1 to fix diagonal jagginess
123
        box_size = self.box_size(widget) + 1
1 by Scott James Remnant
Commit the first version of bzrk.
124
256.4.1 by Gary van der Merwe
* Set a width and use ellips on Revision No column.
125
        width = box_size * (self.columns_len + 1)
1 by Scott James Remnant
Commit the first version of bzrk.
126
        height = box_size
127
128
        # FIXME I have no idea how to use cell_area properly
129
        return (0, 0, width, height)
130
131
    def on_render(self, window, widget, bg_area, cell_area, exp_area, flags):
132
        """Render an individual cell.
133
134
        Draws the cell contents using cairo, taking care to clip what we
135
        do to within the background area so we don't draw over other cells.
136
        Note that we're a bit naughty there and should really be drawing
137
        in the cell_area (or even the exposed area), but we explicitly don't
138
        want any gutter.
139
140
        We try and be a little clever, if the line we need to draw is going
141
        to cross other columns we actually draw it as in the .---' style
142
        instead of a pure diagonal ... this reduces confusion by an
143
        incredible amount.
144
        """
145
        ctx = window.cairo_create()
146
        ctx.rectangle(bg_area.x, bg_area.y, bg_area.width, bg_area.height)
147
        ctx.clip()
148
6 by Scott James Remnant
Also increase the width of the lines in accordance with the font size.
149
        box_size = self.box_size(widget)
150
9 by Scott James Remnant
Fix the busted font size stuff, and then increase the sizes a bit to
151
        ctx.set_line_width(box_size / 8)
1 by Scott James Remnant
Commit the first version of bzrk.
152
153
        # Draw lines into the cell
154
        for start, end, colour in self.in_lines:
256.2.7 by Gary van der Merwe
Use nice Bézier curves for viz
155
            self.render_line (ctx, cell_area, box_size,
156
                         bg_area.y, bg_area.height,
450.9.1 by Daniel Schierbeck
Made the graph cell renderer draw in white when the row is selected.
157
                         start, end, colour, flags)
1 by Scott James Remnant
Commit the first version of bzrk.
158
159
        # Draw lines out of the cell
160
        for start, end, colour in self.out_lines:
256.2.7 by Gary van der Merwe
Use nice Bézier curves for viz
161
            self.render_line (ctx, cell_area, box_size,
162
                         bg_area.y + bg_area.height, bg_area.height,
450.9.1 by Daniel Schierbeck
Made the graph cell renderer draw in white when the row is selected.
163
                         start, end, colour, flags)
1 by Scott James Remnant
Commit the first version of bzrk.
164
165
        # Draw the revision node in the right column
166
        (column, colour) = self.node
167
        ctx.arc(cell_area.x + box_size * column + box_size / 2,
168
                cell_area.y + cell_area.height / 2,
9 by Scott James Remnant
Fix the busted font size stuff, and then increase the sizes a bit to
169
                box_size / 4, 0, 2 * math.pi)
1 by Scott James Remnant
Commit the first version of bzrk.
170
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
171
        if flags & Gtk.CELL_RENDERER_SELECTED:
450.9.1 by Daniel Schierbeck
Made the graph cell renderer draw in white when the row is selected.
172
            ctx.set_source_rgb(1.0, 1.0, 1.0)
450.9.3 by Daniel Schierbeck
Made the line graph be stroked with white instead of filled.
173
            ctx.set_line_width(box_size / 4)
174
            ctx.stroke_preserve()
175
            ctx.set_line_width(box_size / 8)
176
177
        self.set_colour(ctx, colour, 0.0, 0.5)
1 by Scott James Remnant
Commit the first version of bzrk.
178
        ctx.stroke_preserve()
179
450.9.3 by Daniel Schierbeck
Made the line graph be stroked with white instead of filled.
180
        self.set_colour(ctx, colour, 0.5, 1.0)
1 by Scott James Remnant
Commit the first version of bzrk.
181
        ctx.fill()
423.5.1 by Ali Sabil
Added tags visualization in the graph
182
183
        self.render_tags(ctx, widget.create_pango_context(), cell_area, box_size)
724 by Jelmer Vernooij
Fix formatting, imports.
184
450.9.1 by Daniel Schierbeck
Made the graph cell renderer draw in white when the row is selected.
185
    def render_line(self, ctx, cell_area, box_size, mid, height, start, end, colour, flags):
256.2.50 by Gary van der Merwe
First implementation of broken lines.
186
        if start is None:
450.9.5 by Daniel Schierbeck
Fixed bug where the broken lines markers were not drawn correctly.
187
            ctx.set_line_cap(cairo.LINE_CAP_ROUND)
256.2.50 by Gary van der Merwe
First implementation of broken lines.
188
            x = cell_area.x + box_size * end + box_size / 2
189
            ctx.move_to(x, mid + height / 3)
190
            ctx.line_to(x, mid + height / 3)
191
            ctx.move_to(x, mid + height / 6)
192
            ctx.line_to(x, mid + height / 6)
724 by Jelmer Vernooij
Fix formatting, imports.
193
256.2.50 by Gary van der Merwe
First implementation of broken lines.
194
        elif end is None:
450.9.5 by Daniel Schierbeck
Fixed bug where the broken lines markers were not drawn correctly.
195
            ctx.set_line_cap(cairo.LINE_CAP_ROUND)
256.2.50 by Gary van der Merwe
First implementation of broken lines.
196
            x = cell_area.x + box_size * start + box_size / 2
197
            ctx.move_to(x, mid - height / 3)
198
            ctx.line_to(x, mid - height / 3)
199
            ctx.move_to(x, mid - height / 6)
200
            ctx.line_to(x, mid - height / 6)
450.9.4 by Daniel Schierbeck
Removed white breaks between joining lines.
201
256.2.7 by Gary van der Merwe
Use nice Bézier curves for viz
202
        else:
450.9.5 by Daniel Schierbeck
Fixed bug where the broken lines markers were not drawn correctly.
203
            ctx.set_line_cap(cairo.LINE_CAP_BUTT)
256.2.50 by Gary van der Merwe
First implementation of broken lines.
204
            startx = cell_area.x + box_size * start + box_size / 2
205
            endx = cell_area.x + box_size * end + box_size / 2
724 by Jelmer Vernooij
Fix formatting, imports.
206
256.2.50 by Gary van der Merwe
First implementation of broken lines.
207
            ctx.move_to(startx, mid - height / 2)
724 by Jelmer Vernooij
Fix formatting, imports.
208
256.2.50 by Gary van der Merwe
First implementation of broken lines.
209
            if start - end == 0 :
450.9.4 by Daniel Schierbeck
Removed white breaks between joining lines.
210
                ctx.line_to(endx, mid + height / 2 + 1)
256.2.50 by Gary van der Merwe
First implementation of broken lines.
211
            else:
212
                ctx.curve_to(startx, mid - height / 5,
213
                             startx, mid - height / 5,
214
                             startx + (endx - startx) / 2, mid)
450.9.5 by Daniel Schierbeck
Fixed bug where the broken lines markers were not drawn correctly.
215
256.2.50 by Gary van der Merwe
First implementation of broken lines.
216
                ctx.curve_to(endx, mid + height / 5,
217
                             endx, mid + height / 5 ,
450.9.5 by Daniel Schierbeck
Fixed bug where the broken lines markers were not drawn correctly.
218
                             endx, mid + height / 2 + 1)
450.9.3 by Daniel Schierbeck
Made the line graph be stroked with white instead of filled.
219
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
220
        if flags & Gtk.CELL_RENDERER_SELECTED:
450.9.1 by Daniel Schierbeck
Made the graph cell renderer draw in white when the row is selected.
221
            ctx.set_source_rgb(1.0, 1.0, 1.0)
450.9.3 by Daniel Schierbeck
Made the line graph be stroked with white instead of filled.
222
            ctx.set_line_width(box_size / 5)
223
            ctx.stroke_preserve()
224
            ctx.set_line_width(box_size / 8)
225
226
        self.set_colour(ctx, colour, 0.0, 0.65)
227
256.2.7 by Gary van der Merwe
Use nice Bézier curves for viz
228
        ctx.stroke()
423.5.1 by Ali Sabil
Added tags visualization in the graph
229
230
    def render_tags(self, ctx, pango_ctx, cell_area, box_size):
423.6.1 by Ali Sabil
Set the tags colour to yellow
231
        # colour ID used in self.set_colour on the tags
232
        TAG_COLOUR_ID = 1
233
423.5.1 by Ali Sabil
Added tags visualization in the graph
234
        (column, colour) = self.node
423.5.9 by Daniel Schierbeck
Fixed bug where markup in tags would cause rendering errors.
235
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
236
        font_desc = Pango.FontDescription()
237
        font_desc.set_size(Pango.SCALE * 7)
423.5.9 by Daniel Schierbeck
Fixed bug where markup in tags would cause rendering errors.
238
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
239
        tag_layout = Pango.Layout(pango_ctx)
423.5.9 by Daniel Schierbeck
Fixed bug where markup in tags would cause rendering errors.
240
        tag_layout.set_font_description(font_desc)
423.5.1 by Ali Sabil
Added tags visualization in the graph
241
423.5.4 by Daniel Schierbeck
Made the tag label stack look good, even with many tags.
242
        # The width of the tag label stack
243
        width = 0
244
423.5.1 by Ali Sabil
Added tags visualization in the graph
245
        for tag_idx, tag in enumerate(self.tags):
423.5.9 by Daniel Schierbeck
Fixed bug where markup in tags would cause rendering errors.
246
            tag_layout.set_text(" " + tag + " ")
423.5.1 by Ali Sabil
Added tags visualization in the graph
247
            text_width, text_height = tag_layout.get_pixel_size()
248
423.5.3 by Daniel Schierbeck
Made tag labels stack horizontally instead of vertically, and added padding to the labels.
249
            x0 = cell_area.x + \
423.5.4 by Daniel Schierbeck
Made the tag label stack look good, even with many tags.
250
                 box_size * (column + 1.3) + width
423.5.3 by Daniel Schierbeck
Made tag labels stack horizontally instead of vertically, and added padding to the labels.
251
423.5.1 by Ali Sabil
Added tags visualization in the graph
252
            y0 = cell_area.y + \
423.5.3 by Daniel Schierbeck
Made tag labels stack horizontally instead of vertically, and added padding to the labels.
253
                 cell_area.height / 2 - \
254
                 text_height / 2
423.5.1 by Ali Sabil
Added tags visualization in the graph
255
423.5.4 by Daniel Schierbeck
Made the tag label stack look good, even with many tags.
256
            width += text_width + 5
257
423.5.1 by Ali Sabil
Added tags visualization in the graph
258
            # Draw the tag border
259
            ctx.move_to(x0 - box_size / 3, y0 + text_height / 2)
260
            ctx.line_to(x0, y0)
261
            ctx.line_to(x0 + text_width, y0)
262
            ctx.line_to(x0 + text_width, y0 + text_height)
263
            ctx.line_to(x0, y0 + text_height)
264
            ctx.line_to(x0 - box_size / 3, y0 + text_height / 2)
265
423.6.2 by Ali Sabil
Enhanced the tag drawing
266
            ctx.new_sub_path()
423.5.7 by Daniel Schierbeck
Made tag label holes larger.
267
            ctx.arc(x0 - box_size / 12,
423.6.2 by Ali Sabil
Enhanced the tag drawing
268
                        y0 + text_height / 2,
423.5.7 by Daniel Schierbeck
Made tag label holes larger.
269
                        box_size / 7,
423.6.2 by Ali Sabil
Enhanced the tag drawing
270
                        0, 2 * math.pi);
271
423.6.1 by Ali Sabil
Set the tags colour to yellow
272
            self.set_colour(ctx, TAG_COLOUR_ID, 0.0, 0.5)
423.5.1 by Ali Sabil
Added tags visualization in the graph
273
            ctx.stroke_preserve()
274
423.6.2 by Ali Sabil
Enhanced the tag drawing
275
            ctx.set_fill_rule (cairo.FILL_RULE_EVEN_ODD)
423.6.1 by Ali Sabil
Set the tags colour to yellow
276
            self.set_colour(ctx, TAG_COLOUR_ID, 0.5, 1.0)
423.5.1 by Ali Sabil
Added tags visualization in the graph
277
            ctx.fill()
278
279
            # Draw the tag text
423.6.1 by Ali Sabil
Set the tags colour to yellow
280
            self.set_colour(ctx, 0, 0.0, 0.0)
423.5.1 by Ali Sabil
Added tags visualization in the graph
281
            ctx.move_to(x0, y0)
282
            ctx.show_layout(tag_layout)
283