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