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