~ubuntu-branches/ubuntu/gutsy/serpentine/gutsy

« back to all changes in this revision

Viewing changes to serpentine/cairopiechart.py

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-08-16 21:15:55 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20070816211555-t0h0nugk2kn1tb61
Tags: 0.9-0ubuntu1
* New upstream version
* debian/control:
  - updated XS-Python-Version value

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
import gtk
2
2
from math import cos, sin
3
3
import math
 
4
import cairo
4
5
 
5
6
TWO_PI = math.pi * 2
6
7
 
11
12
_gety = lambda y, radius, angle: y + sin(angle) * radius
12
13
_getxy = lambda center, radius, angle: (_getx(center[X], radius, angle), _gety(center[Y], radius, angle))
13
14
 
14
 
def sketch_arc(ctx, center, radius, offset, apperture):
15
 
    
16
 
    angle1 = offset
17
 
    angle2 = offset + apperture
18
 
    corner1 = _getxy(center, radius, angle1)
19
 
    corner2 = _getxy(center, radius, angle2)
20
 
    
21
 
    ctx.move_to(*center)
22
 
    ctx.line_to(*corner1)
23
 
    ctx.arc(center[X], center[Y], radius, angle1, angle2)
24
 
    ctx.line_to(center[X], center[Y])
25
 
 
26
 
def sketch_radius(ctx, center, radius, angle):
27
 
    ctx.move_to(*center)
28
 
    ctx.line_to(*_getxy(center, radius, angle))
29
 
 
30
 
 
31
 
class CairoPieChart(gtk.DrawingArea):
32
 
    def __init__(self, values, getter):
33
 
        super(CairoPieChart, self).__init__()
34
 
        self.connect("expose-event", self._on_exposed)
35
 
        self.values = values
36
 
        self.selected = []
37
 
        self.getter = getter
38
 
        self.values = values
39
 
    
40
 
 
41
 
    def _on_exposed(self, me, evt):
42
 
        self.draw(evt)
43
 
    
44
 
    def draw_slice(self, center, radius, offset, percentage, color, ctx):
45
 
        offset *= math.pi * 2
46
 
        apperture = percentage * math.pi * 2
47
 
        
48
 
        ctx.set_source_color(color)
49
 
        sketch_arc(ctx, center, radius, offset, apperture)
 
15
class Slice(object):
 
16
    def __init__(self, center, radius, offset, apperture):
 
17
        # the center of the slice
 
18
        self.center = center
 
19
        # the length of the radius
 
20
        self.radius = radius
 
21
        # the angular offset
 
22
        self.offset = offset
 
23
        # relative angle of the slice
 
24
        self.apperture = apperture
 
25
        # apperture counting from 'o' to 'offset'
 
26
        self.angle1 = offset
 
27
        # final apperture
 
28
        self.angle2 = offset + apperture
 
29
        # big point
 
30
        self.corner1 = _getxy(center, radius, self.angle1)
 
31
        # small point
 
32
        self.corner2 = _getxy(center, radius, self.angle2)
 
33
 
 
34
    def split(self, parts):
 
35
        apperture = self.apperture/parts
 
36
        new_Slice = lambda x: Slice(self.center, self.radius, self.offset + x, apperture)
 
37
        val = 0
 
38
        for x in range(parts):
 
39
            yield new_Slice(val)
 
40
            val += apperture
 
41
 
 
42
    def split2(self, parts):
 
43
        apperture = self.apperture/parts
 
44
        new_Slice = lambda x: Slice(self.center, self.radius, self.offset, apperture + x)
 
45
        val = 0
 
46
        for x in range(parts):
 
47
            yield new_Slice(val)
 
48
            val += apperture
 
49
    
 
50
 
 
51
def color_to_rgba(color, alpha=1.0):
 
52
    """
 
53
    Converts a GdkColor to a tuple in the rgba format.
 
54
    You can pass an optional argument for the alpha,
 
55
    since it defaults to 1.0.
 
56
    """
 
57
    return (color.red/65535.0,
 
58
            color.green/65535.0,
 
59
            color.blue/65535.0,
 
60
            alpha)
 
61
 
 
62
def create_fade_pattern(p1, p2, r, g, b, a=1.0):
 
63
    """Creates a pattern that is fading."""
 
64
    patt = cairo.LinearGradient(p1[0], p1[1], p2[0], p2[1])
 
65
    patt.add_color_stop_rgba(0.0, r, g, b, 0)
 
66
    patt.add_color_stop_rgba(0.7, r, g, b, .8)
 
67
    patt.add_color_stop_rgba(0.0, r, g, b, 0)
 
68
    
 
69
    return patt
 
70
 
 
71
def sketch_arc(ctx, s):
 
72
    ctx.move_to(*s.center)
 
73
    ctx.line_to(*s.corner1)
 
74
    ctx.arc(s.center[X], s.center[Y], s.radius, s.angle1, s.angle2)
 
75
    ctx.line_to(s.center[X], s.center[Y])
 
76
 
 
77
def sketch_radius(ctx, center, corner):
 
78
    ctx.move_to(*center)
 
79
    ctx.line_to(*corner)
 
80
 
 
81
def _draw_interior(ctx, s, color):
 
82
    # Draw interior
 
83
    ctx.set_source_color(color)
 
84
    sketch_arc(ctx, s)
 
85
    ctx.close_path()
 
86
    ctx.fill()
 
87
 
 
88
 
 
89
def _draw_interior_fade(ctx, s, color):
 
90
    apperture_1 = s.apperture * 0.90
 
91
    s1 = Slice(s.center, s.radius, s.offset, apperture_1)
 
92
    s2 = Slice(s.center, s.radius, s.offset + apperture_1, s.apperture - apperture_1)
 
93
    
 
94
    # Draw interior
 
95
    ctx.set_source_color(color)
 
96
    sketch_arc(ctx, s1)
 
97
    ctx.close_path()
 
98
    ctx.fill()
 
99
 
 
100
    # Draw fade
 
101
    rgba = list(color_to_rgba(color))
 
102
    rgba[-1] = 0.30
 
103
    for small_s in s2.split2(8):
 
104
        #ctx.set_source_color(color)
 
105
        ctx.set_source_rgba(*rgba)
 
106
        sketch_arc(ctx, small_s)
50
107
        ctx.close_path()
51
108
        ctx.fill()
52
 
        
53
 
        ctx.set_source_color(self.get_border_color())
54
 
        sketch_radius(ctx, center, radius, offset)
55
 
        ctx.stroke()
56
 
 
57
 
    def draw_background(self, center, radius, ctx):
58
 
        ctx.set_source_color(self.style.bg[gtk.STATE_NORMAL])
59
 
        ctx.arc(center[X], center[Y], radius, 0, TWO_PI)
60
 
        ctx.fill()
61
 
 
62
 
    def draw_border(self, center, radius, ctx):
63
 
        ctx.set_source_color(self.get_border_color())
64
 
        ctx.arc(center[X], center[Y], radius, 0, TWO_PI)
65
 
        ctx.stroke()
66
 
 
 
109
 
 
110
def draw_slice(ctx, center, radius, offset, percentage, color, border_color, fade=False):
 
111
    # Obtain the apperture of the slice
 
112
    offset *= math.pi * 2
 
113
    apperture = percentage * math.pi * 2
 
114
    s = Slice(center, radius, offset, apperture)
 
115
    if fade:
 
116
        _draw_interior_fade(ctx, s, color)
 
117
    else:
 
118
        _draw_interior(ctx, s, color)
 
119
 
 
120
    # Draw border
 
121
    ctx.set_source_color(border_color)
 
122
    sketch_radius(ctx, s.center, s.corner1)
 
123
    ctx.stroke()
 
124
 
 
125
class CairoWidget(gtk.DrawingArea):
 
126
    """Base class for using cairo graphics"""
 
127
    def __init__(self):
 
128
        super(CairoWidget, self).__init__()
 
129
        self.connect("expose-event",
 
130
                     lambda widget, evt: \
 
131
                     self.draw(self.window.cairo_create()))
67
132
        
68
133
    def get_border_color(self):
69
134
        return self.style.dark[gtk.STATE_NORMAL]
80
145
    def get_background_color(self):
81
146
        return self.style.bg[gtk.STATE_NORMAL]
82
147
 
83
 
 
84
 
       
85
 
    def draw(self, evt):
 
148
    def draw(self, ctx):
 
149
        raise NotImplementedError("You must implement 'draw(ctx)' method")
 
150
 
 
151
class CairoPieChart(CairoWidget):
 
152
    """Draws a group of slices that represent musics"""
 
153
    def __init__(self, values, getter):
 
154
        super(CairoPieChart, self).__init__()
 
155
        self.values = values
 
156
        self.selected = []
 
157
        self.getter = getter
 
158
        self.values = values
 
159
    
 
160
 
 
161
    def draw_slice(self, ctx, center, radius, offset, percentage, color):
 
162
        draw_slice(ctx, center, radius, offset, percentage, color, self.get_border_color())
 
163
 
 
164
    def draw_background(self, center, radius, ctx):
 
165
        ctx.set_source_color(self.get_background_color())
 
166
        ctx.arc(center[X], center[Y], radius, 0, TWO_PI)
 
167
        ctx.fill()
 
168
 
 
169
    def draw_border(self, center, radius, ctx):
 
170
        ctx.set_source_color(self.get_border_color())
 
171
        ctx.arc(center[X], center[Y], radius, 0, TWO_PI)
 
172
        ctx.stroke()
 
173
 
 
174
    def get_color_for(self, index):
 
175
        selected = index in self.selected
 
176
 
 
177
        if selected:
 
178
            color = self.get_selected_background_color()
 
179
        else:
 
180
            color = self.get_normal_background_color()
 
181
        return color
 
182
    
 
183
    def draw(self, ctx):
86
184
        rect = self.allocation
 
185
        
87
186
        radius = min(rect.width / 2.0, rect.height / 2.0) - 5
88
187
        if radius <= 0:
89
188
            return
91
190
        x = rect.width / 2.0
92
191
        y = rect.height / 2.0
93
192
        center = (x, y)
94
 
        
 
193
        ctx.set_line_width(0.75)
 
194
 
 
195
        # the small radius is 20% of the radius
95
196
        small_radius = radius * 0.20
96
197
        
97
 
        ctx = self.window.cairo_create()
98
 
        ctx.set_line_width(0.75)
99
 
 
100
 
        offset = 0.0
 
198
 
 
199
        # Calculate total from all the values on the source
101
200
        total = 0
102
201
        for val in self.values:
103
202
            total += self.getter(val)
105
204
            total = self.total
106
205
        total = float(total)
107
206
 
 
207
        offset = 0.0
 
208
        
 
209
        # cycle for each slice
108
210
        for index, val in enumerate(self.values):
 
211
            # get the percentage each slice occupies
109
212
            apperture = self.getter(val) / total
110
 
            selected = index in self.selected
111
 
 
112
 
            if selected:
113
 
                bg = self.get_selected_background_color()
114
 
            else:
115
 
                bg = self.get_normal_background_color()
116
 
                
117
 
                
118
 
            self.draw_slice(center, radius, offset, apperture, bg, ctx)
 
213
            
 
214
            color = self.get_color_for(index)
 
215
            self.draw_slice(ctx, center, radius, offset, apperture, color)
119
216
            offset += apperture
120
217
        
121
218
        if offset < 1:
122
 
            bg = self.get_empty_background_color()
123
 
            self.draw_slice(center, radius, offset, 1.0 - offset, bg, ctx)
 
219
            color = self.get_empty_background_color()
 
220
            self.draw_slice(ctx, center, radius, offset, 1.0 - offset, color)
124
221
 
125
222
        self.draw_background(center, small_radius, ctx)
126
223
        self.draw_border(center, small_radius, ctx)
127
224
        self.draw_border(center, radius, ctx)
128
225
 
129
226
 
 
227
def bling(chart):
 
228
    
 
229
    chart.values[0] += 0.1
 
230
    chart.values[1] -= 0.1
 
231
    if chart.values[1] < 0 or chart.values[0] > 22:
 
232
        chart.values[0] = 22
 
233
        chart.values[1] = 0
 
234
    chart.queue_draw()
 
235
    
 
236
    return chart.values[1] > 0
130
237
 
131
238
 
132
239
def main():
 
240
    import gobject
133
241
    window = gtk.Window()
134
242
    chart = CairoPieChart([10,12], lambda x: x)
135
 
    chart.total = 22
 
243
    chart.total = 30
136
244
    chart.selected = [0]
137
245
    chart.show()
138
 
    chart.set_size_request(64, 64)
 
246
    chart.set_size_request(256, 256)
139
247
 
140
248
    btn = gtk.Button("Hi")
141
249
    btn.show()
144
252
    vbox.add(btn)
145
253
    vbox.add(chart)
146
254
    window.add(vbox)
147
 
 
 
255
    gobject.timeout_add(100, bling, chart)
 
256
    
148
257
    #window.add(chart)
149
258
    window.connect("destroy", gtk.main_quit)
150
259
    window.show()