]> Pileus Git - ~andy/gtk/blob - gtk/gtkcellrendererprogress.c
This commit includes a fix for #169463, Stefan Kost.
[~andy/gtk] / gtk / gtkcellrendererprogress.c
1 /* gtkcellrendererprogress.c
2  * Copyright (C) 2002 Naba Kumar <kh_naba@users.sourceforge.net>
3  * heavily modified by Jörgen Scheibengruber <mfcn@gmx.de>
4  * heavily modified by Marco Pesenti Gritti <marco@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /*
22  * Modified by the GTK+ Team and others 1997-2004.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "config.h"
29 #include <stdlib.h>
30
31 #include "gtkcellrendererprogress.h"
32 #include "gtkprivate.h"
33 #include "gtkintl.h"
34 #include "gtkalias.h"
35
36 #define GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object),                        \
37                                                                                      GTK_TYPE_CELL_RENDERER_PROGRESS, \
38                                                                                      GtkCellRendererProgressPrivate))
39
40 enum
41 {
42         PROP_0,
43         PROP_VALUE,
44         PROP_TEXT
45 }; 
46
47 struct _GtkCellRendererProgressPrivate
48 {
49   gint value;
50   gchar *text;
51   gchar *label;
52   gint min_h;
53   gint min_w;
54 };
55
56 static void gtk_cell_renderer_progress_finalize     (GObject                 *object);
57 static void gtk_cell_renderer_progress_get_property (GObject                 *object,
58                                                      guint                    param_id,
59                                                      GValue                  *value,
60                                                      GParamSpec              *pspec);
61 static void gtk_cell_renderer_progress_set_property (GObject                 *object,
62                                                      guint                    param_id,
63                                                      const GValue            *value,
64                                                      GParamSpec              *pspec);
65 static void gtk_cell_renderer_progress_set_value    (GtkCellRendererProgress *cellprogress,
66                                                      gint                     value);
67 static void gtk_cell_renderer_progress_set_text     (GtkCellRendererProgress *cellprogress,
68                                                      const gchar             *text);
69 static void compute_dimensions                      (GtkCellRenderer         *cell,
70                                                      GtkWidget               *widget,
71                                                      const gchar             *text,
72                                                      gint                    *width,
73                                                      gint                    *height);
74 static void gtk_cell_renderer_progress_get_size     (GtkCellRenderer         *cell,
75                                                      GtkWidget               *widget,
76                                                      GdkRectangle            *cell_area,
77                                                      gint                    *x_offset,
78                                                      gint                    *y_offset,
79                                                      gint                    *width,
80                                                      gint                    *height);
81 static void gtk_cell_renderer_progress_render       (GtkCellRenderer         *cell,
82                                                      GdkWindow               *window,
83                                                      GtkWidget               *widget,
84                                                      GdkRectangle            *background_area,
85                                                      GdkRectangle            *cell_area,
86                                                      GdkRectangle            *expose_area,
87                                                      guint                    flags);
88
89      
90 G_DEFINE_TYPE (GtkCellRendererProgress, gtk_cell_renderer_progress, GTK_TYPE_CELL_RENDERER);
91
92 static void
93 gtk_cell_renderer_progress_class_init (GtkCellRendererProgressClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
97   
98   object_class->finalize = gtk_cell_renderer_progress_finalize;
99   object_class->get_property = gtk_cell_renderer_progress_get_property;
100   object_class->set_property = gtk_cell_renderer_progress_set_property;
101   
102   cell_class->get_size = gtk_cell_renderer_progress_get_size;
103   cell_class->render = gtk_cell_renderer_progress_render;
104   
105   /**
106    * GtkCellRendererProgress:value:
107    * 
108    * The "value" property determines the percentage to which the
109    * progress bar will be "filled in". 
110    *
111    * Since: 2.6
112    **/
113   g_object_class_install_property (object_class,
114                                    PROP_VALUE,
115                                    g_param_spec_int ("value",
116                                                      P_("Value"),
117                                                      P_("Value of the progress bar"),
118                                                      0, 100, 0,
119                                                      GTK_PARAM_READWRITE));
120
121   /**
122    * GtkCellRendererProgress:text:
123    * 
124    * The "text" property determines the label which will be drawn
125    * over the progress bar. Setting this property to %NULL causes the default 
126    * label to be displayed. Setting this property to an empty string causes 
127    * no label to be displayed.
128    *
129    * Since: 2.6
130    **/
131   g_object_class_install_property (object_class,
132                                    PROP_TEXT,
133                                    g_param_spec_string ("text",
134                                                         P_("Text"),
135                                                         P_("Text on the progress bar"),
136                                                         NULL,
137                                                         GTK_PARAM_READWRITE));
138
139   g_type_class_add_private (object_class, 
140                             sizeof (GtkCellRendererProgressPrivate));
141 }
142
143 static void
144 gtk_cell_renderer_progress_init (GtkCellRendererProgress *cellprogress)
145 {
146   cellprogress->priv = GTK_CELL_RENDERER_PROGRESS_GET_PRIVATE (cellprogress);
147   cellprogress->priv->value = 0;
148   cellprogress->priv->text = NULL;
149   cellprogress->priv->label = NULL;
150   cellprogress->priv->min_w = -1;
151   cellprogress->priv->min_h = -1;
152 }
153
154
155 /**
156  * gtk_cell_renderer_progress_new:
157  * 
158  * Creates a new #GtkCellRendererProgress. 
159  *
160  * Return value: the new cell renderer
161  *
162  * Since: 2.6
163  **/
164 GtkCellRenderer*
165 gtk_cell_renderer_progress_new (void)
166 {
167   return g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, NULL);
168 }
169
170 static void
171 gtk_cell_renderer_progress_finalize (GObject *object)
172 {
173   GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
174   
175   g_free (cellprogress->priv->text);
176   g_free (cellprogress->priv->label);
177   
178   G_OBJECT_CLASS (gtk_cell_renderer_progress_parent_class)->finalize (object);
179 }
180
181 static void
182 gtk_cell_renderer_progress_get_property (GObject *object,
183                                          guint param_id,
184                                          GValue *value,
185                                          GParamSpec *pspec)
186 {
187   GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
188   
189   switch (param_id)
190     {
191     case PROP_VALUE:
192       g_value_set_int (value, cellprogress->priv->value);
193       break;
194     case PROP_TEXT:
195       g_value_set_string (value, cellprogress->priv->text);
196       break;
197     default:
198       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
199     }
200 }
201
202 static void
203 gtk_cell_renderer_progress_set_property (GObject *object,
204                                          guint param_id,
205                                          const GValue *value,
206                                          GParamSpec   *pspec)
207 {
208   GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
209   
210   switch (param_id)
211     {
212     case PROP_VALUE:
213       gtk_cell_renderer_progress_set_value (cellprogress, 
214                                             g_value_get_int (value));
215       break;
216     case PROP_TEXT:
217       gtk_cell_renderer_progress_set_text (cellprogress,
218                                            g_value_get_string (value));
219       break;
220     default:
221       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
222     }
223 }
224
225 static void
226 gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress, 
227                                       gint                     value)
228 {
229   gchar *text;
230   
231   cellprogress->priv->value = value;
232
233   if (cellprogress->priv->text)
234     text = g_strdup (cellprogress->priv->text);
235   else
236     /* do not translate the part before the | */
237     text = g_strdup_printf (Q_("progress bar label|%d %%"), 
238                             cellprogress->priv->value);
239   
240   g_free (cellprogress->priv->label);
241   cellprogress->priv->label = text;
242 }
243
244 static void
245 gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress, 
246                                      const gchar             *text)
247 {
248   gchar *new_text;
249
250   new_text = g_strdup (text);
251   g_free (cellprogress->priv->text);
252   cellprogress->priv->text = new_text;
253
254   /* Update the label */
255   gtk_cell_renderer_progress_set_value (cellprogress, cellprogress->priv->value);
256 }
257
258 static void
259 compute_dimensions (GtkCellRenderer *cell,
260                     GtkWidget       *widget, 
261                     const gchar     *text, 
262                     gint            *width, 
263                     gint            *height)
264 {
265   PangoRectangle logical_rect;
266   PangoLayout *layout;
267   
268   layout = gtk_widget_create_pango_layout (widget, text);
269   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
270   
271   if (width)
272     *width = logical_rect.width + cell->xpad * 2 + widget->style->xthickness * 2;
273   
274   if (height)
275     *height = logical_rect.height + cell->ypad * 2 + widget->style->ythickness * 2;
276   
277   g_object_unref (layout);
278 }
279
280 static void
281 gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell,
282                                      GtkWidget       *widget,
283                                      GdkRectangle    *cell_area,
284                                      gint            *x_offset,
285                                      gint            *y_offset,
286                                      gint            *width,
287                                      gint            *height)
288 {
289   GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
290   gint w, h;
291   gchar *text;
292
293   if (cellprogress->priv->min_w < 0)
294     {
295       text = g_strdup_printf (Q_("progress bar label|%d %%"), 100);
296       compute_dimensions (cell, widget, text,
297                           &cellprogress->priv->min_w,
298                           &cellprogress->priv->min_h);
299       g_free (text);
300     }
301   
302   compute_dimensions (cell, widget, cellprogress->priv->label, &w, &h);
303   
304   if (width)
305     *width = MAX (cellprogress->priv->min_w, w);
306   
307   if (height)
308     *height = MIN (cellprogress->priv->min_h, h);
309
310   /* FIXME: at the moment cell_area is only set when we are requesting
311    * the size for drawing the focus rectangle. We now just return
312    * the last size we used for drawing the progress bar, which will
313    * work for now. Not a really nice solution though.
314    */
315   if (cell_area)
316     {
317       if (width)
318         *width = cell_area->width;
319       if (height)
320         *height = cell_area->height;
321     }
322 }
323
324 static void
325 gtk_cell_renderer_progress_render (GtkCellRenderer *cell,
326                                    GdkWindow       *window,
327                                    GtkWidget       *widget,
328                                    GdkRectangle    *background_area,
329                                    GdkRectangle    *cell_area,
330                                    GdkRectangle    *expose_area,
331                                    guint            flags)
332 {
333   GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
334   PangoLayout *layout;
335   PangoRectangle logical_rect;
336   gint x, y, w, h, perc_w, pos;
337   GdkRectangle clip;
338   gboolean is_rtl;
339   cairo_t *cr;
340
341   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
342   
343   cr = gdk_cairo_create (window);
344   
345   x = cell_area->x + cell->xpad;
346   y = cell_area->y + cell->ypad;
347   
348   w = cell_area->width - cell->xpad * 2;
349   h = cell_area->height - cell->ypad * 2;
350
351   cairo_rectangle (cr, x, y, w, h);
352   gdk_cairo_set_source_color (cr, &widget->style->fg[GTK_STATE_NORMAL]);
353   cairo_fill (cr);
354   
355   x += widget->style->xthickness;
356   y += widget->style->ythickness;
357   w -= widget->style->xthickness * 2;
358   h -= widget->style->ythickness * 2;
359   
360   cairo_rectangle (cr, x, y, w, h);
361   gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]);
362   cairo_fill (cr);
363   
364   perc_w = w * MAX (0, cellprogress->priv->value) / 100;
365   
366   cairo_rectangle (cr, is_rtl ? (x + w - perc_w) : x, y, perc_w, h);
367   gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]);
368   cairo_fill (cr);
369   
370   layout = gtk_widget_create_pango_layout (widget, cellprogress->priv->label);
371   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
372   
373   pos = (w - logical_rect.width)/2;
374   
375   clip.x = x;
376   clip.y = y;
377   clip.width = is_rtl ? w - perc_w : perc_w;
378   clip.height = h; 
379
380   gtk_paint_layout (widget->style, window, 
381                     is_rtl ? GTK_STATE_NORMAL : GTK_STATE_SELECTED,
382                     FALSE, &clip, widget, "progressbar",
383                     x + pos, y + (h - logical_rect.height)/2,
384                     layout);
385
386   clip.x = clip.x + clip.width;
387   clip.width = w - clip.width;
388
389   gtk_paint_layout (widget->style, window, 
390                     is_rtl ?  GTK_STATE_SELECTED : GTK_STATE_NORMAL,
391                     FALSE, &clip, widget, "progressbar",
392                     x + pos, y + (h - logical_rect.height)/2,
393                     layout);
394   
395   g_object_unref (layout);
396   cairo_destroy (cr);
397 }
398
399 #define __GTK_CELL_RENDERER_PROGRESS_C__
400 #include "gtkaliasdef.c"