1 /* baobab-cell-renderer-progress.c
2  *
3  * Copyright (C) 2006 Paolo Borelli
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #include "config.h"
22 #include <stdlib.h>
23 
24 #include "baobab-cell-renderer-progress.h"
25 
26 #define BAOBAB_CELL_RENDERER_PROGRESS_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object),                        \
27                                                            BAOBAB_TYPE_CELL_RENDERER_PROGRESS, \
28                                                            BaobabCellRendererProgressPrivate))
29 
30 enum
31 {
32   PROP_0,
33   PROP_PERC
34 };
35 
36 struct _BaobabCellRendererProgressPrivate
37 {
38   double perc;
39 };
40 
G_DEFINE_TYPE(BaobabCellRendererProgress,baobab_cell_renderer_progress,GTK_TYPE_CELL_RENDERER)41 G_DEFINE_TYPE (BaobabCellRendererProgress, baobab_cell_renderer_progress, GTK_TYPE_CELL_RENDERER)
42 
43 static void
44 baobab_cell_renderer_progress_init (BaobabCellRendererProgress *cellprogress)
45 {
46   cellprogress->priv = BAOBAB_CELL_RENDERER_PROGRESS_GET_PRIVATE (cellprogress);
47   cellprogress->priv->perc = 0;
48 
49   g_object_set (cellprogress,
50                 "mode", GTK_CELL_RENDERER_MODE_INERT,
51 		NULL);
52   gtk_cell_renderer_set_padding (GTK_CELL_RENDERER (cellprogress), 4, 4);
53 }
54 
55 GtkCellRenderer*
baobab_cell_renderer_progress_new(void)56 baobab_cell_renderer_progress_new (void)
57 {
58   return g_object_new (BAOBAB_TYPE_CELL_RENDERER_PROGRESS, NULL);
59 }
60 
61 static void
baobab_cell_renderer_progress_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)62 baobab_cell_renderer_progress_get_property (GObject *object,
63 					    guint param_id,
64 					    GValue *value,
65 					    GParamSpec *pspec)
66 {
67   BaobabCellRendererProgress *cellprogress = BAOBAB_CELL_RENDERER_PROGRESS (object);
68 
69   switch (param_id)
70     {
71     case PROP_PERC:
72       g_value_set_double (value, cellprogress->priv->perc);
73       break;
74     default:
75       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
76     }
77 }
78 
79 static void
baobab_cell_renderer_progress_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)80 baobab_cell_renderer_progress_set_property (GObject *object,
81 					    guint param_id,
82 					    const GValue *value,
83 					    GParamSpec   *pspec)
84 {
85   BaobabCellRendererProgress *cellprogress = BAOBAB_CELL_RENDERER_PROGRESS (object);
86 
87   switch (param_id)
88     {
89     case PROP_PERC:
90       cellprogress->priv->perc = g_value_get_double (value);
91       break;
92     default:
93       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
94     }
95 }
96 
97 /* we simply have a fixed size */
98 
99 #define FIXED_WIDTH   70
100 #define FIXED_HEIGHT  8
101 
102 static void
baobab_cell_renderer_progress_get_size(GtkCellRenderer * cell,GtkWidget * widget,const GdkRectangle * cell_area,gint * x_offset,gint * y_offset,gint * width,gint * height)103 baobab_cell_renderer_progress_get_size (GtkCellRenderer *cell,
104 					GtkWidget       *widget,
105 					const GdkRectangle    *cell_area,
106 					gint            *x_offset,
107 					gint            *y_offset,
108 					gint            *width,
109 					gint            *height)
110 {
111   gint calc_width, calc_height;
112   gint xpad, ypad;
113   gfloat xalign, yalign;
114 
115   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
116 
117   calc_width  = xpad * 2 + FIXED_WIDTH;
118   calc_height = ypad * 2 + FIXED_HEIGHT;
119 
120   if (width)
121     *width = calc_width;
122 
123   if (height)
124     *height = calc_height;
125 
126   gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
127   if (cell_area)
128   {
129     if (x_offset)
130     {
131       *x_offset = xalign * (cell_area->width - calc_width);
132       *x_offset = MAX (*x_offset, 0);
133     }
134 
135     if (y_offset)
136     {
137       *y_offset = yalign * (cell_area->height - calc_height);
138       *y_offset = MAX (*y_offset, 0);
139     }
140   }
141 }
142 
143 static void
set_color_according_to_perc(cairo_t * cr,double value)144 set_color_according_to_perc (cairo_t *cr, double value)
145 {
146   static GdkColor red;
147   static GdkColor yellow;
148   static GdkColor green;
149   static gboolean colors_initialized = FALSE;
150 
151   if (!colors_initialized)
152     {
153       /* hardcoded tango colors */
154       gdk_color_parse ("#cc0000", &red);
155       gdk_color_parse ("#edd400", &yellow);
156       gdk_color_parse ("#73d216", &green);
157 
158       colors_initialized = TRUE;
159     }
160 
161   if (value <= 0)
162     {
163       cairo_set_source_rgb (cr, 1, 1, 1);
164       return;
165     }
166   else if (value <= 33.33)
167     {
168       gdk_cairo_set_source_color (cr, &green);
169       return;
170     }
171   else if (value <= 66.66)
172     {
173       gdk_cairo_set_source_color (cr, &yellow);
174       return;
175     }
176   else if (value <= 100.0)
177     {
178       gdk_cairo_set_source_color (cr, &red);
179       return;
180     }
181   else
182     g_assert_not_reached ();
183 }
184 
185 static void
baobab_cell_renderer_progress_render(GtkCellRenderer * cell,cairo_t * cr,GtkWidget * widget,const GdkRectangle * background_area,const GdkRectangle * cell_area,GtkCellRendererState flags)186 baobab_cell_renderer_progress_render (GtkCellRenderer *cell,
187 				      cairo_t         *cr,
188 				      GtkWidget       *widget,
189 				      const GdkRectangle    *background_area,
190 				      const GdkRectangle    *cell_area,
191 				      GtkCellRendererState flags)
192 {
193   BaobabCellRendererProgress *cellprogress = BAOBAB_CELL_RENDERER_PROGRESS (cell);
194   gint x, y, w, h, perc_w;
195   gint xpad, ypad;
196   gboolean is_rtl;
197 
198   is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
199 
200   gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
201   x = cell_area->x + xpad;
202   y = cell_area->y + ypad;
203 
204   w = cell_area->width - xpad * 2;
205   h = cell_area->height - ypad * 2;
206 
207   /*
208    * we always use a white bar with black
209    * border and green/yellow/red progress...
210    * I know it's not theme friendly, but we don't
211    * want a plain progress bar
212    */
213 
214   cairo_rectangle (cr, x, y, w, h);
215   cairo_set_source_rgb (cr, 1, 1, 1);
216   cairo_fill (cr);
217 
218   perc_w = w * MAX (0, cellprogress->priv->perc) / 100;
219 
220   cairo_rectangle (cr, is_rtl ? (x + w - perc_w) : x, y, perc_w, h);
221   set_color_according_to_perc (cr, cellprogress->priv->perc);
222   cairo_fill (cr);
223 
224   cairo_rectangle (cr, x, y, w, h);
225   cairo_set_source_rgb (cr, 0, 0, 0);
226   cairo_fill (cr);
227 }
228 
229 static void
baobab_cell_renderer_progress_class_init(BaobabCellRendererProgressClass * klass)230 baobab_cell_renderer_progress_class_init (BaobabCellRendererProgressClass *klass)
231 {
232   GObjectClass *object_class = G_OBJECT_CLASS (klass);
233   GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
234 
235   object_class->get_property = baobab_cell_renderer_progress_get_property;
236   object_class->set_property = baobab_cell_renderer_progress_set_property;
237 
238   cell_class->get_size = baobab_cell_renderer_progress_get_size;
239   cell_class->render = baobab_cell_renderer_progress_render;
240 
241   g_object_class_install_property (object_class,
242 				   PROP_PERC,
243 				   g_param_spec_double ("perc",
244 						        "percentage",
245 						        "precentage",
246 						        -1, 100, 0,
247 						        G_PARAM_READWRITE));
248 
249   g_type_class_add_private (object_class,
250 			    sizeof (BaobabCellRendererProgressPrivate));
251 }
252