~ubuntu-branches/ubuntu/hardy/emesene/hardy-proposed

« back to all changes in this revision

Viewing changes to FancyAvatarRenderer.py

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2008-02-06 21:57:05 UTC
  • Revision ID: james.westby@ubuntu.com-20080206215705-d1abf07rdwcaju3p
Tags: upstream-1.0~r1013
ImportĀ upstreamĀ versionĀ 1.0~r1013

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
#   This file is part of emesene.
 
4
#
 
5
#    Emesene is free software; you can redistribute it and/or modify
 
6
#    it under the terms of the GNU General Public License as published by
 
7
#    the Free Software Foundation; either version 2 of the License, or
 
8
#    (at your option) any later version.
 
9
#
 
10
#    emesene is distributed in the hope that it will be useful,
 
11
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
#    GNU General Public License for more details.
 
14
#
 
15
#    You should have received a copy of the GNU General Public License
 
16
#    along with emesene; if not, write to the Free Software
 
17
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 
 
19
import gtk
 
20
import gtk.gdk
 
21
import cairo
 
22
import gobject
 
23
 
 
24
class FancyAvatarRenderer ( gtk.GenericCellRenderer ):
 
25
    """Renderer for avatar """
 
26
    
 
27
    __gproperties__ = {
 
28
        'pixbuf': (gtk.gdk.Pixbuf, 'Pixbuf','Pixbuf',gobject.PARAM_READWRITE),        
 
29
        'blocked': (bool , 'User Blocked status', '',False, gobject.PARAM_READWRITE),        
 
30
        'dimention' : (gobject.TYPE_INT, 'cell dimentions', 'height width of cell', 0, 96, 32, gobject.PARAM_READWRITE),
 
31
        'status': (str, 'Contact status', '','FLN', gobject.PARAM_READWRITE),
 
32
        'radius_factor' : (gobject.TYPE_FLOAT,'radius of pixbuf', 
 
33
        '0.0 to 0.5 with 0.1 = 10% of dimention',0.0, 0.5,0.11, gobject.PARAM_READWRITE),
 
34
         }         
 
35
        
 
36
    def __init__(self, controller, cellDimention = 32, cellRadius = 0.11):
 
37
        #gobject.GObject.__init__(self)
 
38
        self.__gobject_init__()
 
39
        self._pixbuf = None
 
40
        self._status = 'FLN'
 
41
        self._blocked = False
 
42
        self._dimention = cellDimention
 
43
        self._radius_factor = cellRadius
 
44
        
 
45
        self.set_property('xpad', 1)
 
46
        self.set_property('ypad', 1)   
 
47
        
 
48
        self._theme = controller.theme
 
49
        self._config = controller.config
 
50
        
 
51
        #set up information of statusTransformation
 
52
        self.__set_transformation(self._config.user['statusTransformation'])
 
53
 
 
54
        self.transId = self._config.connect('change::statusTransformation', \
 
55
            self.__transformation_callback)
 
56
        
 
57
    def destroy(self):
 
58
        self._config.disconnect(self.transId)
 
59
        gtk.GenericCellRenderer.destroy(self)
 
60
 
 
61
    def __set_transformation(self, setting):
 
62
        transformation = setting.split('|')                   
 
63
        if 'pixelate' in transformation: self._pixalated = True  
 
64
        else: self._pixalated = False
 
65
        if 'corner' in transformation: self._corner = True  
 
66
        else: self._corner = False        
 
67
        if 'alpha' in transformation: self._alpha_status = True  
 
68
        else: self._alpha_status = False
 
69
        if 'mini' in transformation: self._mini = True  
 
70
        else: self._mini = False
 
71
 
 
72
    def __transformation_callback(self, config, newvalue, oldvalue):
 
73
        self.__set_transformation(newvalue)
 
74
        
 
75
    def do_get_property(self, property):
 
76
        if property.name == 'pixbuf':
 
77
            return self._pixbuf
 
78
        elif property.name == 'dimention':
 
79
            return self._dimention
 
80
        elif property.name == 'radius-factor':
 
81
            return self._radius_factor
 
82
        elif property.name == 'blocked':
 
83
            return self._blocked
 
84
        elif property.name == 'status':
 
85
            return self._status                        
 
86
        else:
 
87
            raise AttributeError, 'unknown property %s' % property.name
 
88
  
 
89
    def do_set_property(self, property, value):
 
90
        if property.name == 'pixbuf':
 
91
            self._pixbuf = value
 
92
        elif property.name == 'dimention':            
 
93
            self._dimention = value
 
94
        elif property.name == 'radius-factor':
 
95
            self._radius_factor = value         
 
96
        elif property.name == 'blocked':
 
97
            self._blocked = value
 
98
        elif property.name == 'status':
 
99
            self._status = value      
 
100
        else:
 
101
            raise AttributeError, 'unknown property %s' % property.name
 
102
 
 
103
    def on_get_size( self, widget, cell_area=None ):       
 
104
        xpad,ypad = self.get_property('xpad'), self.get_property('ypad')
 
105
        if self._dimention >= 32: width = self._dimention
 
106
        elif self._mini: width = self._dimention
 
107
        elif self._corner: width = self._dimention * 2            
 
108
        else: width = self._dimention        
 
109
        height = self._dimention + (ypad *2)                       
 
110
        return ( 0, 0,  width, height) 
 
111
        
 
112
    def on_render( self, window, widget, background_area, cell_area, expose_area, flags ):        
 
113
        avatar = self._pixbuf
 
114
        overlay = None
 
115
        alpha = 1
 
116
                 
 
117
        if self._pixalated: avatar = __getPixalate(self._pixbuf)            
 
118
        if self._corner: overlay = self.__getOverlay()
 
119
        if self._alpha_status: alpha = self.__getAlpha()
 
120
        
 
121
        xpad,ypad = self.get_property('xpad'), self.get_property('ypad')
 
122
        cell_x, cell_y, cell_width, cell_height = cell_area 
 
123
        ctx = window.cairo_create()          
 
124
        ctx.translate(cell_x,cell_y)
 
125
        
 
126
        if not avatar == None:
 
127
            self.__drawScalePixbuf( ctx,avatar,cell_width - self._dimention,ypad ,self._dimention, 
 
128
                gtk.ANCHOR_CENTER, self._radius_factor, alpha)
 
129
        
 
130
        if not overlay == None:       
 
131
            if self._dimention >= 32 :     
 
132
                self.__drawScalePixbuf( ctx,overlay,cell_width - 16, ypad + self._dimention - 16,16, position = gtk.ANCHOR_SW)
 
133
            elif self._mini:
 
134
                self.__drawScalePixbuf( ctx,overlay,cell_width - 8, ypad + self._dimention - 8,8, position = gtk.ANCHOR_SW)
 
135
            else:
 
136
                self.__drawScalePixbuf( ctx,overlay,0,ypad  ,16)
 
137
             
 
138
    def __getAlpha(self):
 
139
        if self._status in ['IDL', 'FLN']: return 0.75
 
140
        else: return 1
 
141
 
 
142
    def __getOverlay(self):
 
143
        if self._blocked:
 
144
            return self._theme.getImage('status-blocked')
 
145
        elif self._status in ['AWY','BRB','LUN','IDL' ] :
 
146
            return self._theme.getImage('status-away')
 
147
        elif self._status in ['BSY','PHN' ] :
 
148
            return self._theme.getImage('status-busy')
 
149
        else:
 
150
            return None       
 
151
            
 
152
    def __getPixalate( self, pixbuf ):
 
153
        pixbuf_to_modify = pixbuf.copy()        
 
154
        if not self._status == 'NLN':
 
155
            if contact.status == 'BSY':
 
156
                pixbuf_to_modify.saturate_and_pixelate(pixbuf,1.0, True)
 
157
            else:
 
158
                pixbuf_to_modify.saturate_and_pixelate(pixbuf,0.1, False)                
 
159
        return pixbuf_to_modify
 
160
        
 
161
          
 
162
    def __drawScalePixbuf(self, ctx, pixbuf, x,y , dimention, position = gtk.ANCHOR_CENTER, radius = 0, alpha = 1 ):
 
163
        
 
164
        ctx.save()
 
165
        ctx.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
 
166
        ctx.translate(x,y)
 
167
        
 
168
        pix_width = pixbuf.get_width()
 
169
        pix_height = pixbuf.get_height()
 
170
        if (pix_width > dimention) or (pix_height > dimention): 
 
171
            scale_factor = float(dimention) / max (pix_width,pix_height)
 
172
        else: 
 
173
            scale_factor = 1        
 
174
        scale_width = pix_width* scale_factor
 
175
        scale_height = pix_height* scale_factor 
 
176
 
 
177
        #tranlate position
 
178
        if position in [gtk.ANCHOR_NW,gtk.ANCHOR_W,gtk.ANCHOR_SW] : x = 0
 
179
        elif position in [gtk.ANCHOR_N,gtk.ANCHOR_CENTER,gtk.ANCHOR_S] : x = (dimention/2) - (scale_width/2)
 
180
        else: x = dimention - scale_width        
 
181
        if position in [gtk.ANCHOR_NW,gtk.ANCHOR_N,gtk.ANCHOR_NE] : y = 0
 
182
        elif position in [gtk.ANCHOR_E,gtk.ANCHOR_CENTER,gtk.ANCHOR_W] : y = (dimention/2) - (scale_height/2)
 
183
        else: y = dimention - scale_height         
 
184
        ctx.translate(x, y)
 
185
            
 
186
        if radius > 0 : 
 
187
            self.__roundedrecMoonlight(ctx,0,0,scale_width,scale_height, self._dimention * radius) 
 
188
            ctx.clip()
 
189
        ctx.scale(scale_factor,scale_factor)
 
190
        ctx.set_source_pixbuf(pixbuf,0,0)
 
191
        ctx.paint_with_alpha(alpha)
 
192
        ctx.restore()
 
193
    
 
194
    def __roundedrecMoonlight(self, cr,x,y,w,h,radius=5):
 
195
        # http://cairographics.org/cookbook/roundedrectangles/
 
196
        # modified from mono moonlight aka mono silverlight
 
197
        # test limits (without using multiplications)
 
198
        # http://graphics.stanford.edu/courses/cs248-98-fall/Final/q1.html
 
199
 
 
200
        ARC_TO_BEZIER = 0.55228475
 
201
        if radius > (min(w,h)/2):
 
202
            radius = (min(w,h)/2)
 
203
        #approximate (quite close) the arc using a bezier curve
 
204
        c = ARC_TO_BEZIER * radius
 
205
 
 
206
        cr.new_path();
 
207
        cr.move_to ( x + radius, y)
 
208
        cr.rel_line_to ( w - 2 * radius, 0.0)
 
209
        cr.rel_curve_to ( c, 0.0, radius, c, radius, radius)
 
210
        cr.rel_line_to ( 0, h - 2 * radius)
 
211
        cr.rel_curve_to ( 0.0, c, c - radius, radius, -radius, radius)
 
212
        cr.rel_line_to ( -w + 2 * radius, 0)
 
213
        cr.rel_curve_to ( -c, 0, -radius, -c, -radius, -radius)
 
214
        cr.rel_line_to (0, -h + 2 * radius)
 
215
        cr.rel_curve_to (0.0, -c, radius - c, -radius, radius, -radius)
 
216
        cr.close_path ()
 
217
                        
 
218
gobject.type_register( FancyAvatarRenderer )