2dff9b2504f6012ddde92b794d7566615dddf7f3
[doldaconnect.git] / clients / gtk2 / progressbar.c
1 /* Taken from the GTK TreeView tutorial on gtk.org.
2  * Slightly modified.
3  */
4
5 #include "progressbar.h"
6
7 /* This is based mainly on GtkCellRendererProgress
8  *  in GAIM, written and (c) 2002 by Sean Egan
9  *  (Licensed under the GPL), which in turn is
10  *  based on Gtk's GtkCellRenderer[Text|Toggle|Pixbuf]
11  *  implementation by Jonathan Blandford */
12
13 /* Some boring function declarations: GObject type system stuff */
14
15 static void     custom_cell_renderer_progress_init       (CustomCellRendererProgress      *cellprogress);
16
17 static void     custom_cell_renderer_progress_class_init (CustomCellRendererProgressClass *klass);
18
19 static void     custom_cell_renderer_progress_get_property  (GObject                    *object,
20                                                              guint                       param_id,
21                                                              GValue                     *value,
22                                                              GParamSpec                 *pspec);
23
24 static void     custom_cell_renderer_progress_set_property  (GObject                    *object,
25                                                              guint                       param_id,
26                                                              const GValue               *value,
27                                                              GParamSpec                 *pspec);
28
29 static void     custom_cell_renderer_progress_finalize (GObject *gobject);
30
31
32 /* These functions are the heart of our custom cell renderer: */
33
34 static void     custom_cell_renderer_progress_get_size   (GtkCellRenderer            *cell,
35                                                           GtkWidget                  *widget,
36                                                           GdkRectangle               *cell_area,
37                                                           gint                       *x_offset,
38                                                           gint                       *y_offset,
39                                                           gint                       *width,
40                                                           gint                       *height);
41
42 static void     custom_cell_renderer_progress_render     (GtkCellRenderer            *cell,
43                                                           GdkWindow                  *window,
44                                                           GtkWidget                  *widget,
45                                                           GdkRectangle               *background_area,
46                                                           GdkRectangle               *cell_area,
47                                                           GdkRectangle               *expose_area,
48                                                           guint                       flags);
49
50
51 enum
52 {
53   PROP_PERCENTAGE = 1,
54 };
55
56 static   gpointer parent_class;
57
58
59 /***************************************************************************
60  *
61  *  custom_cell_renderer_progress_get_type: here we register our type with
62  *                                          the GObject type system if we
63  *                                          haven't done so yet. Everything
64  *                                          else is done in the callbacks.
65  *
66  ***************************************************************************/
67
68 GType
69 custom_cell_renderer_progress_get_type (void)
70 {
71     static GType cell_progress_type = 0;
72
73     if (cell_progress_type)
74         return cell_progress_type;
75
76     if (1)
77     {
78         static const GTypeInfo cell_progress_info =
79             {
80                 sizeof (CustomCellRendererProgressClass),
81                 NULL,                                                     /* base_init */
82                 NULL,                                                     /* base_finalize */
83                 (GClassInitFunc) custom_cell_renderer_progress_class_init,
84                 NULL,                                                     /* class_finalize */
85                 NULL,                                                     /* class_data */
86                 sizeof (CustomCellRendererProgress),
87                 0,                                                        /* n_preallocs */
88                 (GInstanceInitFunc) custom_cell_renderer_progress_init,
89             };
90
91         /* Derive from GtkCellRenderer */
92         cell_progress_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
93                                                      "CustomCellRendererProgress",
94                                                      &cell_progress_info,
95                                                      0);
96     }
97
98     return cell_progress_type;
99 }
100
101
102 /***************************************************************************
103  *
104  *  custom_cell_renderer_progress_init: set some default properties of the
105  *                                      parent (GtkCellRenderer).
106  *
107  ***************************************************************************/
108
109 static void
110 custom_cell_renderer_progress_init (CustomCellRendererProgress *cellrendererprogress)
111 {
112     GTK_CELL_RENDERER(cellrendererprogress)->mode = GTK_CELL_RENDERER_MODE_INERT;
113     GTK_CELL_RENDERER(cellrendererprogress)->xpad = 2;
114     GTK_CELL_RENDERER(cellrendererprogress)->ypad = 2;
115 }
116
117
118 /***************************************************************************
119  *
120  *  custom_cell_renderer_progress_class_init:
121  *
122  *  set up our own get_property and set_property functions, and
123  *  override the parent's functions that we need to implement.
124  *  And make our new "percentage" property known to the type system.
125  *  If you want cells that can be activated on their own (ie. not
126  *  just the whole row selected) or cells that are editable, you
127  *  will need to override 'activate' and 'start_editing' as well.
128  *
129  ***************************************************************************/
130
131 static void
132 custom_cell_renderer_progress_class_init (CustomCellRendererProgressClass *klass)
133 {
134     GtkCellRendererClass *cell_class   = GTK_CELL_RENDERER_CLASS(klass);
135     GObjectClass         *object_class = G_OBJECT_CLASS(klass);
136
137     parent_class           = g_type_class_peek_parent (klass);
138     object_class->finalize = custom_cell_renderer_progress_finalize;
139
140     /* Hook up functions to set and get our
141      *   custom cell renderer properties */
142     object_class->get_property = custom_cell_renderer_progress_get_property;
143     object_class->set_property = custom_cell_renderer_progress_set_property;
144
145     /* Override the two crucial functions that are the heart
146      *   of a cell renderer in the parent class */
147     cell_class->get_size = custom_cell_renderer_progress_get_size;
148     cell_class->render   = custom_cell_renderer_progress_render;
149
150     /* Install our very own properties */
151     g_object_class_install_property (object_class,
152                                      PROP_PERCENTAGE,
153                                      g_param_spec_double ("percentage",
154                                                           "Percentage",
155                                                           "The fractional progress to display",
156                                                           0, 1, 0,
157                                                           G_PARAM_READWRITE));
158 }
159
160
161 /***************************************************************************
162  *
163  *  custom_cell_renderer_progress_finalize: free any resources here
164  *
165  ***************************************************************************/
166
167 static void
168 custom_cell_renderer_progress_finalize (GObject *object)
169 {
170 /*
171   CustomCellRendererProgress *cellrendererprogress = CUSTOM_CELL_RENDERER_PROGRESS(object);
172 */
173
174     /* Free any dynamically allocated resources here */
175
176     (* G_OBJECT_CLASS (parent_class)->finalize) (object);
177 }
178
179
180 /***************************************************************************
181  *
182  *  custom_cell_renderer_progress_get_property: as it says
183  *
184  ***************************************************************************/
185
186 static void
187 custom_cell_renderer_progress_get_property (GObject    *object,
188                                             guint       param_id,
189                                             GValue     *value,
190                                             GParamSpec *psec)
191 {
192   CustomCellRendererProgress  *cellprogress = CUSTOM_CELL_RENDERER_PROGRESS(object);
193
194   switch (param_id)
195   {
196     case PROP_PERCENTAGE:
197       g_value_set_double(value, cellprogress->progress);
198       break;
199
200     default:
201       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, psec);
202       break;
203   }
204 }
205
206
207 /***************************************************************************
208  *
209  *  custom_cell_renderer_progress_set_property: as it says
210  *
211  ***************************************************************************/
212
213 static void
214 custom_cell_renderer_progress_set_property (GObject      *object,
215                                             guint         param_id,
216                                             const GValue *value,
217                                             GParamSpec   *pspec)
218 {
219     CustomCellRendererProgress *cellprogress = CUSTOM_CELL_RENDERER_PROGRESS (object);
220
221     switch (param_id)
222     {
223     case PROP_PERCENTAGE:
224         cellprogress->progress = g_value_get_double(value);
225         break;
226
227     default:
228         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
229         break;
230     }
231 }
232
233 /***************************************************************************
234  *
235  *  custom_cell_renderer_progress_new: return a new cell renderer instance
236  *
237  ***************************************************************************/
238
239 GtkCellRenderer *
240 custom_cell_renderer_progress_new (void)
241 {
242     return g_object_new(CUSTOM_TYPE_CELL_RENDERER_PROGRESS, NULL);
243 }
244
245
246 /***************************************************************************
247  *
248  *  custom_cell_renderer_progress_get_size: crucial - calculate the size
249  *                                          of our cell, taking into account
250  *                                          padding and alignment properties
251  *                                          of parent.
252  *
253  ***************************************************************************/
254
255 #define FIXED_WIDTH   100
256 #define FIXED_HEIGHT  12
257
258 static void
259 custom_cell_renderer_progress_get_size (GtkCellRenderer *cell,
260                                         GtkWidget       *widget,
261                                         GdkRectangle    *cell_area,
262                                         gint            *x_offset,
263                                         gint            *y_offset,
264                                         gint            *width,
265                                         gint            *height)
266 {
267     gint calc_width;
268     gint calc_height;
269
270     calc_width  = (gint) cell->xpad * 2 + FIXED_WIDTH;
271     calc_height = (gint) cell->ypad * 2 + FIXED_HEIGHT;
272
273     if (width)
274         *width = calc_width;
275
276     if (height)
277         *height = calc_height;
278
279     if (cell_area)
280     {
281         if (x_offset)
282         {
283             *x_offset = cell->xalign * (cell_area->width - calc_width);
284             *x_offset = MAX (*x_offset, 0);
285         }
286
287         if (y_offset)
288         {
289             *y_offset = cell->yalign * (cell_area->height - calc_height);
290             *y_offset = MAX (*y_offset, 0);
291         }
292     }
293 }
294
295
296 /***************************************************************************
297  *
298  *  custom_cell_renderer_progress_render: crucial - do the rendering.
299  *
300  ***************************************************************************/
301
302 static void
303 custom_cell_renderer_progress_render (GtkCellRenderer *cell,
304                                       GdkWindow       *window,
305                                       GtkWidget       *widget,
306                                       GdkRectangle    *background_area,
307                                       GdkRectangle    *cell_area,
308                                       GdkRectangle    *expose_area,
309                                       guint            flags)
310 {
311     CustomCellRendererProgress *cellprogress = CUSTOM_CELL_RENDERER_PROGRESS (cell);
312     GtkStateType                state;
313     gint                        width, height;
314     gint                        x_offset, y_offset;
315
316     custom_cell_renderer_progress_get_size (cell, widget, cell_area,
317                                             &x_offset, &y_offset,
318                                             &width, &height);
319
320     if (GTK_WIDGET_HAS_FOCUS (widget))
321         state = GTK_STATE_ACTIVE;
322     else
323         state = GTK_STATE_NORMAL;
324
325     width  -= cell->xpad*2;
326     height -= cell->ypad*2;
327
328     gtk_paint_box (widget->style,
329                    window,
330                    GTK_STATE_NORMAL, GTK_SHADOW_IN,
331                    NULL, widget, "trough",
332                    cell_area->x + x_offset + cell->xpad,
333                    cell_area->y + y_offset + cell->ypad,
334                    width - 1, height - 1);
335
336     gtk_paint_box (widget->style,
337                    window,
338                    state, GTK_SHADOW_OUT,
339                    NULL, widget, "bar",
340                    cell_area->x + x_offset + cell->xpad,
341                    cell_area->y + y_offset + cell->ypad,
342                    width * cellprogress->progress,
343                    height - 1);
344 }