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>
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.
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.
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.
22 * Modified by the GTK+ Team and others 1997-2007. 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/.
31 #include "gtkcellrendererprogress.h"
32 #include "gtkprogressbar.h"
33 #include "gtkprivate.h"
48 struct _GtkCellRendererProgressPrivate
59 GtkProgressBarOrientation orientation;
62 static void gtk_cell_renderer_progress_finalize (GObject *object);
63 static void gtk_cell_renderer_progress_get_property (GObject *object,
67 static void gtk_cell_renderer_progress_set_property (GObject *object,
71 static void gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress,
73 static void gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress,
75 static void gtk_cell_renderer_progress_set_pulse (GtkCellRendererProgress *cellprogress,
77 static void compute_dimensions (GtkCellRenderer *cell,
82 static void gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell,
84 GdkRectangle *cell_area,
89 static void gtk_cell_renderer_progress_render (GtkCellRenderer *cell,
92 GdkRectangle *background_area,
93 GdkRectangle *cell_area,
94 GdkRectangle *expose_area,
98 G_DEFINE_TYPE (GtkCellRendererProgress, gtk_cell_renderer_progress, GTK_TYPE_CELL_RENDERER)
101 gtk_cell_renderer_progress_class_init (GtkCellRendererProgressClass *klass)
103 GObjectClass *object_class = G_OBJECT_CLASS (klass);
104 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
106 object_class->finalize = gtk_cell_renderer_progress_finalize;
107 object_class->get_property = gtk_cell_renderer_progress_get_property;
108 object_class->set_property = gtk_cell_renderer_progress_set_property;
110 cell_class->get_size = gtk_cell_renderer_progress_get_size;
111 cell_class->render = gtk_cell_renderer_progress_render;
114 * GtkCellRendererProgress:value:
116 * The "value" property determines the percentage to which the
117 * progress bar will be "filled in".
121 g_object_class_install_property (object_class,
123 g_param_spec_int ("value",
125 P_("Value of the progress bar"),
127 GTK_PARAM_READWRITE));
130 * GtkCellRendererProgress:text:
132 * The "text" property determines the label which will be drawn
133 * over the progress bar. Setting this property to %NULL causes the default
134 * label to be displayed. Setting this property to an empty string causes
135 * no label to be displayed.
139 g_object_class_install_property (object_class,
141 g_param_spec_string ("text",
143 P_("Text on the progress bar"),
145 GTK_PARAM_READWRITE));
148 * GtkCellRendererProgress:pulse:
150 * Setting this to a non-negative value causes the cell renderer to
151 * enter "activity mode", where a block bounces back and forth to
152 * indicate that some progress is made, without specifying exactly how
155 * Each increment of the property causes the block to move by a little
158 * To indicate that the activity has not started yet, set the property
159 * to zero. To indicate completion, set the property to %G_MAXINT.
163 g_object_class_install_property (object_class,
165 g_param_spec_int ("pulse",
167 P_("Set this to positive values to indicate that some progress is made, but you don't know how much."),
169 GTK_PARAM_READWRITE));
172 * GtkCellRendererProgress:text-xalign:
174 * The "text-xalign" property controls the horizontal alignment of the
175 * text in the progress bar. Valid values range from 0 (left) to 1
176 * (right). Reserved for RTL layouts.
180 g_object_class_install_property (object_class,
182 g_param_spec_float ("text-xalign",
183 P_("Text x alignment"),
184 P_("The horizontal text alignment, from 0 (left) to 1 (right). Reversed for RTL layouts."),
186 GTK_PARAM_READWRITE));
189 * GtkCellRendererProgress:text-yalign:
191 * The "text-yalign" property controls the vertical alignment of the
192 * text in the progress bar. Valid values range from 0 (top) to 1
197 g_object_class_install_property (object_class,
199 g_param_spec_float ("text-yalign",
200 P_("Text y alignment"),
201 P_("The vertical text alignment, from 0 (top) to 1 (bottom)."),
203 GTK_PARAM_READWRITE));
206 * GtkCellRendererProgress:orientation:
208 * The "orientation" property controls the direction and growth
209 * direction of the progress bar (left-to-right, right-to-left,
210 * top-to-bottom or bottom-to-top).
214 g_object_class_install_property (object_class,
216 g_param_spec_enum ("orientation",
218 P_("Orientation and growth direction of the progress bar"),
219 GTK_TYPE_PROGRESS_BAR_ORIENTATION,
220 GTK_PROGRESS_LEFT_TO_RIGHT,
221 GTK_PARAM_READWRITE));
224 g_type_class_add_private (object_class,
225 sizeof (GtkCellRendererProgressPrivate));
229 gtk_cell_renderer_progress_init (GtkCellRendererProgress *cellprogress)
231 GtkCellRendererProgressPrivate *priv;
233 cellprogress->priv = G_TYPE_INSTANCE_GET_PRIVATE (cellprogress,
234 GTK_TYPE_CELL_RENDERER_PROGRESS,
235 GtkCellRendererProgressPrivate);
236 priv = cellprogress->priv;
246 priv->text_xalign = 0.5;
247 priv->text_yalign = 0.5;
249 priv->orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
254 * gtk_cell_renderer_progress_new:
256 * Creates a new #GtkCellRendererProgress.
258 * Return value: the new cell renderer
263 gtk_cell_renderer_progress_new (void)
265 return g_object_new (GTK_TYPE_CELL_RENDERER_PROGRESS, NULL);
269 gtk_cell_renderer_progress_finalize (GObject *object)
271 GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
272 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
275 g_free (priv->label);
277 G_OBJECT_CLASS (gtk_cell_renderer_progress_parent_class)->finalize (object);
281 gtk_cell_renderer_progress_get_property (GObject *object,
286 GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
287 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
292 g_value_set_int (value, priv->value);
295 g_value_set_string (value, priv->text);
298 g_value_set_int (value, priv->pulse);
300 case PROP_TEXT_XALIGN:
301 g_value_set_float (value, priv->text_xalign);
303 case PROP_TEXT_YALIGN:
304 g_value_set_float (value, priv->text_yalign);
306 case PROP_ORIENTATION:
307 g_value_set_enum (value, priv->orientation);
310 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
315 gtk_cell_renderer_progress_set_property (GObject *object,
320 GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (object);
321 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
326 gtk_cell_renderer_progress_set_value (cellprogress,
327 g_value_get_int (value));
330 gtk_cell_renderer_progress_set_text (cellprogress,
331 g_value_get_string (value));
334 gtk_cell_renderer_progress_set_pulse (cellprogress,
335 g_value_get_int (value));
337 case PROP_TEXT_XALIGN:
338 priv->text_xalign = g_value_get_float (value);
340 case PROP_TEXT_YALIGN:
341 priv->text_yalign = g_value_get_float (value);
343 case PROP_ORIENTATION:
344 priv->orientation = g_value_get_enum (value);
347 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
352 recompute_label (GtkCellRendererProgress *cellprogress)
354 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
358 label = g_strdup (priv->text);
359 else if (priv->pulse < 0)
360 label = g_strdup_printf (C_("progress bar label", "%d %%"), priv->value);
364 g_free (priv->label);
369 gtk_cell_renderer_progress_set_value (GtkCellRendererProgress *cellprogress,
372 cellprogress->priv->value = value;
374 recompute_label (cellprogress);
378 gtk_cell_renderer_progress_set_text (GtkCellRendererProgress *cellprogress,
383 new_text = g_strdup (text);
384 g_free (cellprogress->priv->text);
385 cellprogress->priv->text = new_text;
387 recompute_label (cellprogress);
391 gtk_cell_renderer_progress_set_pulse (GtkCellRendererProgress *cellprogress,
394 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
396 if (pulse != priv->pulse)
401 priv->offset = pulse;
406 recompute_label (cellprogress);
410 compute_dimensions (GtkCellRenderer *cell,
416 PangoRectangle logical_rect;
420 layout = gtk_widget_create_pango_layout (widget, text);
421 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
423 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
426 *width = logical_rect.width + xpad * 2;
429 *height = logical_rect.height + ypad * 2;
431 g_object_unref (layout);
435 gtk_cell_renderer_progress_get_size (GtkCellRenderer *cell,
437 GdkRectangle *cell_area,
443 GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
444 GtkCellRendererProgressPrivate *priv = cellprogress->priv;
450 text = g_strdup_printf (C_("progress bar label", "%d %%"), 100);
451 compute_dimensions (cell, widget, text,
457 compute_dimensions (cell, widget, priv->label, &w, &h);
460 *width = MAX (priv->min_w, w);
463 *height = MIN (priv->min_h, h);
465 /* FIXME: at the moment cell_area is only set when we are requesting
466 * the size for drawing the focus rectangle. We now just return
467 * the last size we used for drawing the progress bar, which will
468 * work for now. Not a really nice solution though.
473 *width = cell_area->width;
475 *height = cell_area->height;
478 if (x_offset) *x_offset = 0;
479 if (y_offset) *y_offset = 0;
483 get_bar_size (gint pulse,
490 bar_size = full_size * MAX (0, value) / 100;
493 else if (pulse == G_MAXINT)
494 bar_size = full_size;
496 bar_size = MAX (2, full_size / 5);
502 get_bar_position (gint start,
511 if (pulse < 0 || pulse == 0 || pulse == G_MAXINT)
513 position = is_rtl ? (start + full_size - bar_size) : start;
517 position = (is_rtl ? offset + 12 : offset) % 24;
519 position = 24 - position;
520 position = start + full_size * position / 15;
527 gtk_cell_renderer_progress_render (GtkCellRenderer *cell,
530 GdkRectangle *background_area,
531 GdkRectangle *cell_area,
532 GdkRectangle *expose_area,
535 GtkCellRendererProgress *cellprogress = GTK_CELL_RENDERER_PROGRESS (cell);
536 GtkCellRendererProgressPrivate *priv= cellprogress->priv;
539 PangoRectangle logical_rect;
540 gint x, y, w, h, x_pos, y_pos, bar_position, bar_size, start, full_size;
545 style = gtk_widget_get_style (widget);
547 is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
549 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
550 x = cell_area->x + xpad;
551 y = cell_area->y + ypad;
552 w = cell_area->width - xpad * 2;
553 h = cell_area->height - ypad * 2;
555 /* FIXME: GtkProgressBar draws the box with "trough" detail,
556 * but some engines don't paint anything with that detail for
557 * non-GtkProgressBar widgets.
559 gtk_paint_box (style,
561 GTK_STATE_NORMAL, GTK_SHADOW_IN,
565 if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT
566 || priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
574 bar_size = get_bar_size (priv->pulse, priv->value, full_size);
576 if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
577 bar_position = get_bar_position (start, full_size, bar_size,
578 priv->pulse, priv->offset, is_rtl);
580 bar_position = get_bar_position (start, full_size, bar_size,
581 priv->pulse, priv->offset, !is_rtl);
583 clip.width = bar_size;
584 clip.x = bar_position;
594 bar_size = get_bar_size (priv->pulse, priv->value, full_size);
596 if (priv->orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
597 bar_position = get_bar_position (start, full_size, bar_size,
598 priv->pulse, priv->offset, TRUE);
600 bar_position = get_bar_position (start, full_size, bar_size,
601 priv->pulse, priv->offset, FALSE);
603 clip.height = bar_size;
604 clip.y = bar_position;
607 gtk_paint_box (style,
609 GTK_STATE_SELECTED, GTK_SHADOW_OUT,
610 &clip, widget, "bar",
612 clip.width, clip.height);
618 layout = gtk_widget_create_pango_layout (widget, priv->label);
619 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
621 if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
622 text_xalign = 1.0 - priv->text_xalign;
624 text_xalign = priv->text_xalign;
626 x_pos = x + style->xthickness + text_xalign *
627 (w - 2 * style->xthickness - logical_rect.width);
629 y_pos = y + style->ythickness + priv->text_yalign *
630 (h - 2 * style->ythickness - logical_rect.height);
632 gtk_paint_layout (style, window,
634 FALSE, &clip, widget, "progressbar",
638 if (bar_position > start)
640 if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT
641 || priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
644 clip.width = bar_position - x;
649 clip.height = bar_position - y;
652 gtk_paint_layout (style, window,
654 FALSE, &clip, widget, "progressbar",
659 if (bar_position + bar_size < start + full_size)
661 if (priv->orientation == GTK_PROGRESS_LEFT_TO_RIGHT
662 || priv->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
664 clip.x = bar_position + bar_size;
665 clip.width = x + w - (bar_position + bar_size);
669 clip.y = bar_position + bar_size;
670 clip.height = y + h - (bar_position + bar_size);
673 gtk_paint_layout (style, window,
675 FALSE, &clip, widget, "progressbar",
680 g_object_unref (layout);