1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2009 Thomas Perl and the gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # draw.py -- Draw routines for gPodder-specific graphics
23 # Thomas Perl <thp@perli.net>, 2007-11-25
33 class TextExtents(object):
34 def __init__(self
, ctx
, text
):
35 tuple = ctx
.text_extents(text
)
36 (self
.x_bearing
, self
.y_bearing
, self
.width
, self
.height
, self
.x_advance
, self
.y_advance
) = tuple
42 def draw_rounded_rectangle(ctx
, x
, y
, w
, h
, r
=10, left_side_width
= None, sides_to_draw
=0, close
=False):
43 if left_side_width
is None:
44 left_side_width
= flw
/2
48 if close
: offset
= 0.5
50 if sides_to_draw
& RRECT_LEFT_SIDE
:
51 ctx
.move_to(x
+int(left_side_width
)-offset
, y
+h
)
53 ctx
.curve_to(x
, y
+h
, x
, y
+h
, x
, y
+h
-r
)
55 ctx
.curve_to(x
, y
, x
, y
, x
+r
, y
)
56 ctx
.line_to(x
+int(left_side_width
)-offset
, y
)
58 ctx
.line_to(x
+int(left_side_width
)-offset
, y
+h
)
60 if sides_to_draw
& RRECT_RIGHT_SIDE
:
61 ctx
.move_to(x
+int(left_side_width
)+offset
, y
)
63 ctx
.curve_to(x
+w
, y
, x
+w
, y
, x
+w
, y
+r
)
64 ctx
.line_to(x
+w
, y
+h
-r
)
65 ctx
.curve_to(x
+w
, y
+h
, x
+w
, y
+h
, x
+w
-r
, y
+h
)
66 ctx
.line_to(x
+int(left_side_width
)+offset
, y
+h
)
68 ctx
.line_to(x
+int(left_side_width
)+offset
, y
)
71 def draw_text_pill(left_text
, right_text
, x
=0, y
=0, border
=4, radius
=14):
72 # Create temporary context to calculate the text size
73 ctx
= cairo
.Context(cairo
.ImageSurface(cairo
.FORMAT_ARGB32
, 1, 1))
75 # Use GTK+ style of a normal Button
76 widget
= gtk
.ProgressBar()
77 style
= widget
.rc_get_style()
79 x_border
= int(border
*1.2)
81 font_desc
= style
.font_desc
82 font_size
= float(1.15*font_desc
.get_size())/float(pango
.SCALE
)
83 font_name
= font_desc
.get_family()
85 ctx
.set_font_size(font_size
)
86 ctx
.select_font_face(font_name
, cairo
.FONT_SLANT_NORMAL
, cairo
.FONT_WEIGHT_BOLD
)
88 left_text_e
= TextExtents(ctx
, left_text
)
89 right_text_e
= TextExtents(ctx
, right_text
)
90 text_height
= max(left_text_e
.height
, right_text_e
.height
)
92 image_height
= int(y
+text_height
+border
*2)
93 image_width
= int(x
+left_text_e
.width
+right_text_e
.width
+x_border
*4)
94 surface
= cairo
.ImageSurface(cairo
.FORMAT_ARGB32
, image_width
, image_height
)
96 ctx
= cairo
.Context(surface
)
97 ctx
.set_font_size(font_size
)
98 ctx
.select_font_face(font_name
, cairo
.FONT_SLANT_NORMAL
, cairo
.FONT_WEIGHT_BOLD
)
102 if right_text
== '0':
105 left_side_width
= left_text_e
.width
+ x_border
*2
106 right_side_width
= right_text_e
.width
+ x_border
*2
108 rect_width
= left_side_width
+ right_side_width
109 rect_height
= text_height
+ border
*2
110 if left_text
is not None:
111 draw_rounded_rectangle(ctx
,x
,y
,rect_width
,rect_height
,radius
, left_side_width
, RRECT_LEFT_SIDE
, right_text
is None)
112 linear
= cairo
.LinearGradient(x
, y
, x
+left_side_width
/2, y
+rect_height
/2)
113 linear
.add_color_stop_rgba(0, .7, .7, .7, .5)
114 linear
.add_color_stop_rgba(1, .4, .4, .4, .5)
115 ctx
.set_source(linear
)
117 ctx
.set_source_rgba(0, 0, 0, .4)
118 ctx
.set_line_width(1)
121 ctx
.move_to(x
+1+x_border
-left_text_e
.x_bearing
, y
+1+border
+text_height
)
122 ctx
.set_source_rgba( 0, 0, 0, 1)
123 ctx
.show_text(left_text
)
124 ctx
.move_to(x
+x_border
-left_text_e
.x_bearing
, y
+border
+text_height
)
125 ctx
.set_source_rgba( 1, 1, 1, 1)
126 ctx
.show_text(left_text
)
128 if right_text
is not None:
129 draw_rounded_rectangle(ctx
, x
, y
, rect_width
, rect_height
, radius
, left_side_width
, RRECT_RIGHT_SIDE
, left_text
is None)
130 linear
= cairo
.LinearGradient(x
+left_side_width
, y
, x
+left_side_width
+right_side_width
/2, y
+rect_height
)
131 linear
.add_color_stop_rgba(0, 0, 0, 0, .9)
132 linear
.add_color_stop_rgba(1, 0, 0, 0, .5)
133 ctx
.set_source(linear
)
135 ctx
.set_source_rgba(0, 0, 0, .7)
136 ctx
.set_line_width(1)
139 ctx
.move_to(x
+1+x_border
*3+left_text_e
.width
-right_text_e
.x_bearing
, y
+1+border
+text_height
)
140 ctx
.set_source_rgba( 0, 0, 0, 1)
141 ctx
.show_text(right_text
)
142 ctx
.move_to(x
+x_border
*3+left_text_e
.width
-right_text_e
.x_bearing
, y
+border
+text_height
)
143 ctx
.set_source_rgba( 1, 1, 1, 1)
144 ctx
.show_text(right_text
)
149 def draw_pill_pixbuf(left_text
, right_text
):
150 return cairo_surface_to_pixbuf(draw_text_pill(left_text
, right_text
))
153 def cairo_surface_to_pixbuf(s
):
155 Converts a Cairo surface to a Gtk Pixbuf by
156 encoding it as PNG and using the PixbufLoader.
158 sio
= StringIO
.StringIO()
162 # Write an empty PNG file to the StringIO, so
163 # in case of an error we have "something" to
164 # load. This happens in PyCairo < 1.1.6, see:
165 # http://webcvs.cairographics.org/pycairo/NEWS?view=markup
166 # Thanks to Chris Arnold for reporting this bug
167 sio
.write('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A\n/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9cMEQkqIyxn3RkAAAAZdEVYdENv\nbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAADUlEQVQI12NgYGBgAAAABQABXvMqOgAAAABJ\nRU5ErkJggg==\n'.decode('base64'))
169 pbl
= gtk
.gdk
.PixbufLoader()
170 pbl
.write(sio
.getvalue())
173 pixbuf
= pbl
.get_pixbuf()
177 def progressbar_pixbuf(width
, height
, percentage
):
178 COLOR_BG
= (.4, .4, .4, .4)
179 COLOR_FG
= (.2, .9, .2, 1.)
180 COLOR_FG_HIGH
= (1., 1., 1., .5)
181 COLOR_BORDER
= (0., 0., 0., 1.)
183 surface
= cairo
.ImageSurface(cairo
.FORMAT_ARGB32
, width
, height
)
184 ctx
= cairo
.Context(surface
)
186 padding
= int(float(width
)/8.0)
187 bar_width
= 2*padding
188 bar_height
= height
- 2*padding
189 bar_height_fill
= bar_height
*percentage
192 ctx
.rectangle(padding
, padding
, bar_width
, bar_height
)
193 ctx
.set_source_rgba(*COLOR_BG
)
197 ctx
.rectangle(padding
, padding
+bar_height
-bar_height_fill
, bar_width
, bar_height_fill
)
198 ctx
.set_source_rgba(*COLOR_FG
)
200 ctx
.rectangle(padding
+bar_width
/3, padding
+bar_height
-bar_height_fill
, bar_width
/4, bar_height_fill
)
201 ctx
.set_source_rgba(*COLOR_FG_HIGH
)
205 ctx
.rectangle(padding
-.5, padding
-.5, bar_width
+1, bar_height
+1)
206 ctx
.set_source_rgba(*COLOR_BORDER
)
207 ctx
.set_line_width(1.)
210 return cairo_surface_to_pixbuf(surface
)