| 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 | } |