1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 #include <glib/gprintf.h>
30 #include "gtkprogress.h"
34 #define DEFAULT_FORMAT "%P %%"
45 static void gtk_progress_class_init (GtkProgressClass *klass);
46 static void gtk_progress_init (GtkProgress *progress);
47 static void gtk_progress_set_property (GObject *object,
51 static void gtk_progress_get_property (GObject *object,
55 static void gtk_progress_destroy (GtkObject *object);
56 static void gtk_progress_finalize (GObject *object);
57 static void gtk_progress_realize (GtkWidget *widget);
58 static gint gtk_progress_expose (GtkWidget *widget,
59 GdkEventExpose *event);
60 static void gtk_progress_size_allocate (GtkWidget *widget,
61 GtkAllocation *allocation);
62 static void gtk_progress_create_pixmap (GtkProgress *progress);
63 static void gtk_progress_value_changed (GtkAdjustment *adjustment,
64 GtkProgress *progress);
67 static GtkWidgetClass *parent_class = NULL;
71 gtk_progress_get_type (void)
73 static GType progress_type = 0;
77 static const GTypeInfo progress_info =
79 sizeof (GtkProgressClass),
81 NULL, /* base_finalize */
82 (GClassInitFunc) gtk_progress_class_init,
83 NULL, /* class_finalize */
84 NULL, /* class_data */
87 (GInstanceInitFunc) gtk_progress_init,
90 progress_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkProgress",
98 gtk_progress_class_init (GtkProgressClass *class)
100 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
101 GtkObjectClass *object_class;
102 GtkWidgetClass *widget_class;
104 object_class = (GtkObjectClass *) class;
105 widget_class = (GtkWidgetClass *) class;
107 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
109 gobject_class->finalize = gtk_progress_finalize;
111 gobject_class->set_property = gtk_progress_set_property;
112 gobject_class->get_property = gtk_progress_get_property;
113 object_class->destroy = gtk_progress_destroy;
115 widget_class->realize = gtk_progress_realize;
116 widget_class->expose_event = gtk_progress_expose;
117 widget_class->size_allocate = gtk_progress_size_allocate;
119 /* to be overridden */
121 class->update = NULL;
122 class->act_mode_enter = NULL;
124 g_object_class_install_property (gobject_class,
126 g_param_spec_boolean ("activity_mode",
128 _("If TRUE the GtkProgress is in activity mode, meaning that it signals something is happening, but not how much of the activity is finished. This is used when you're doing something that you don't know how long it will take"),
132 g_object_class_install_property (gobject_class,
134 g_param_spec_boolean ("show_text",
136 _("Whether the progress is shown as text"),
140 g_object_class_install_property (gobject_class,
142 g_param_spec_float ("text_xalign",
143 _("Text x alignment"),
144 _("A number between 0.0 and 1.0 specifying the horizontal alignment of the text in the progress widget"),
149 g_object_class_install_property (gobject_class,
151 g_param_spec_float ("text_yalign",
152 _("Text y alignment"),
153 _("A number between 0.0 and 1.0 specifying the vertical alignment of the text in the progress widget"),
161 gtk_progress_set_property (GObject *object,
166 GtkProgress *progress;
168 progress = GTK_PROGRESS (object);
172 case PROP_ACTIVITY_MODE:
173 gtk_progress_set_activity_mode (progress, g_value_get_boolean (value));
176 gtk_progress_set_show_text (progress, g_value_get_boolean (value));
178 case PROP_TEXT_XALIGN:
179 gtk_progress_set_text_alignment (progress,
180 g_value_get_float (value),
183 case PROP_TEXT_YALIGN:
184 gtk_progress_set_text_alignment (progress,
186 g_value_get_float (value));
189 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195 gtk_progress_get_property (GObject *object,
200 GtkProgress *progress;
202 progress = GTK_PROGRESS (object);
206 case PROP_ACTIVITY_MODE:
207 g_value_set_boolean (value, (progress->activity_mode != FALSE));
210 g_value_set_boolean (value, (progress->show_text != FALSE));
212 case PROP_TEXT_XALIGN:
213 g_value_set_float (value, progress->x_align);
215 case PROP_TEXT_YALIGN:
216 g_value_set_float (value, progress->y_align);
219 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
225 gtk_progress_init (GtkProgress *progress)
227 progress->adjustment = NULL;
228 progress->offscreen_pixmap = NULL;
229 progress->format = g_strdup (DEFAULT_FORMAT);
230 progress->x_align = 0.5;
231 progress->y_align = 0.5;
232 progress->show_text = FALSE;
233 progress->activity_mode = FALSE;
234 progress->use_text_format = TRUE;
238 gtk_progress_realize (GtkWidget *widget)
240 GtkProgress *progress;
241 GdkWindowAttr attributes;
242 gint attributes_mask;
244 g_return_if_fail (GTK_IS_PROGRESS (widget));
246 progress = GTK_PROGRESS (widget);
247 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
249 attributes.window_type = GDK_WINDOW_CHILD;
250 attributes.x = widget->allocation.x;
251 attributes.y = widget->allocation.y;
252 attributes.width = widget->allocation.width;
253 attributes.height = widget->allocation.height;
254 attributes.wclass = GDK_INPUT_OUTPUT;
255 attributes.visual = gtk_widget_get_visual (widget);
256 attributes.colormap = gtk_widget_get_colormap (widget);
257 attributes.event_mask = gtk_widget_get_events (widget);
258 attributes.event_mask |= GDK_EXPOSURE_MASK;
260 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
262 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
263 &attributes, attributes_mask);
264 gdk_window_set_user_data (widget->window, progress);
266 widget->style = gtk_style_attach (widget->style, widget->window);
267 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
269 gtk_progress_create_pixmap (progress);
273 gtk_progress_destroy (GtkObject *object)
275 GtkProgress *progress;
277 g_return_if_fail (GTK_IS_PROGRESS (object));
279 progress = GTK_PROGRESS (object);
281 if (progress->adjustment)
283 g_signal_handlers_disconnect_by_func (progress->adjustment,
284 gtk_progress_value_changed,
286 g_object_unref (progress->adjustment);
287 progress->adjustment = NULL;
290 GTK_OBJECT_CLASS (parent_class)->destroy (object);
294 gtk_progress_finalize (GObject *object)
296 GtkProgress *progress;
298 g_return_if_fail (GTK_IS_PROGRESS (object));
300 progress = GTK_PROGRESS (object);
302 if (progress->offscreen_pixmap)
303 g_object_unref (progress->offscreen_pixmap);
305 if (progress->format)
306 g_free (progress->format);
308 G_OBJECT_CLASS (parent_class)->finalize (object);
312 gtk_progress_expose (GtkWidget *widget,
313 GdkEventExpose *event)
315 g_return_val_if_fail (GTK_IS_PROGRESS (widget), FALSE);
316 g_return_val_if_fail (event != NULL, FALSE);
318 if (GTK_WIDGET_DRAWABLE (widget))
319 gdk_draw_drawable (widget->window,
320 widget->style->black_gc,
321 GTK_PROGRESS (widget)->offscreen_pixmap,
322 event->area.x, event->area.y,
323 event->area.x, event->area.y,
331 gtk_progress_size_allocate (GtkWidget *widget,
332 GtkAllocation *allocation)
334 g_return_if_fail (GTK_IS_PROGRESS (widget));
335 g_return_if_fail (allocation != NULL);
337 widget->allocation = *allocation;
339 if (GTK_WIDGET_REALIZED (widget))
341 gdk_window_move_resize (widget->window,
342 allocation->x, allocation->y,
343 allocation->width, allocation->height);
345 gtk_progress_create_pixmap (GTK_PROGRESS (widget));
350 gtk_progress_create_pixmap (GtkProgress *progress)
354 g_return_if_fail (GTK_IS_PROGRESS (progress));
356 if (GTK_WIDGET_REALIZED (progress))
358 widget = GTK_WIDGET (progress);
360 if (progress->offscreen_pixmap)
361 g_object_unref (progress->offscreen_pixmap);
363 progress->offscreen_pixmap = gdk_pixmap_new (widget->window,
364 widget->allocation.width,
365 widget->allocation.height,
367 GTK_PROGRESS_GET_CLASS (progress)->paint (progress);
372 gtk_progress_value_changed (GtkAdjustment *adjustment,
373 GtkProgress *progress)
375 GTK_PROGRESS_GET_CLASS (progress)->update (progress);
379 gtk_progress_build_string (GtkProgress *progress,
383 gchar buf[256] = { 0 };
384 gchar tmp[256] = { 0 };
389 src = progress->format;
391 /* This is the new supported version of this function */
392 if (!progress->use_text_format)
393 return g_strdup (src);
395 /* And here's all the deprecated goo. */
411 c = *(src + sizeof(gchar));
414 if (c >= '0' && c <= '2')
416 digits = (gint) (c - '0');
418 c = *(src + sizeof(gchar));
432 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
433 g_snprintf (tmp, sizeof (tmp), fmt, 100 * percentage);
436 g_snprintf (tmp, sizeof (tmp), "%.0f", 100 * percentage);
438 dest = &(buf[strlen (buf)]);
445 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
446 g_snprintf (tmp, sizeof (tmp), fmt, value);
449 g_snprintf (tmp, sizeof (tmp), "%.0f", value);
451 dest = &(buf[strlen (buf)]);
458 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
459 g_snprintf (tmp, sizeof (tmp), fmt, progress->adjustment->lower);
462 g_snprintf (tmp, sizeof (tmp), "%.0f", progress->adjustment->lower);
464 dest = &(buf[strlen (buf)]);
471 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
472 g_snprintf (tmp, sizeof (tmp), fmt, progress->adjustment->upper);
475 g_snprintf (tmp, sizeof (tmp), "%.0f", progress->adjustment->upper);
477 dest = &(buf[strlen (buf)]);
487 return g_strdup (buf);
490 /***************************************************************/
493 gtk_progress_set_adjustment (GtkProgress *progress,
494 GtkAdjustment *adjustment)
496 g_return_if_fail (GTK_IS_PROGRESS (progress));
498 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
500 adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 100, 0, 0, 0);
502 if (progress->adjustment != adjustment)
504 if (progress->adjustment)
506 g_signal_handlers_disconnect_by_func (progress->adjustment,
507 gtk_progress_value_changed,
509 g_object_unref (progress->adjustment);
511 progress->adjustment = adjustment;
514 g_object_ref (adjustment);
515 gtk_object_sink (GTK_OBJECT (adjustment));
516 g_signal_connect (adjustment, "value_changed",
517 G_CALLBACK (gtk_progress_value_changed),
524 gtk_progress_configure (GtkProgress *progress,
530 gboolean changed = FALSE;
532 g_return_if_fail (GTK_IS_PROGRESS (progress));
533 g_return_if_fail (min <= max);
534 g_return_if_fail (value >= min && value <= max);
536 if (!progress->adjustment)
537 gtk_progress_set_adjustment (progress, NULL);
538 adj = progress->adjustment;
540 if (fabs (adj->lower - min) > EPSILON || fabs (adj->upper - max) > EPSILON)
547 gtk_adjustment_value_changed (adj);
549 gtk_adjustment_changed (adj);
553 gtk_progress_set_percentage (GtkProgress *progress,
556 g_return_if_fail (GTK_IS_PROGRESS (progress));
557 g_return_if_fail (percentage >= 0 && percentage <= 1.0);
559 if (!progress->adjustment)
560 gtk_progress_set_adjustment (progress, NULL);
561 gtk_progress_set_value (progress, progress->adjustment->lower + percentage *
562 (progress->adjustment->upper - progress->adjustment->lower));
566 gtk_progress_get_current_percentage (GtkProgress *progress)
568 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
570 if (!progress->adjustment)
571 gtk_progress_set_adjustment (progress, NULL);
573 return ((progress->adjustment->value - progress->adjustment->lower) /
574 (progress->adjustment->upper - progress->adjustment->lower));
578 gtk_progress_get_percentage_from_value (GtkProgress *progress,
581 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
583 if (!progress->adjustment)
584 gtk_progress_set_adjustment (progress, NULL);
586 if (value >= progress->adjustment->lower &&
587 value <= progress->adjustment->upper)
588 return (value - progress->adjustment->lower) /
589 (progress->adjustment->upper - progress->adjustment->lower);
595 gtk_progress_set_value (GtkProgress *progress,
598 g_return_if_fail (GTK_IS_PROGRESS (progress));
600 if (!progress->adjustment)
601 gtk_progress_set_adjustment (progress, NULL);
603 if (fabs (progress->adjustment->value - value) > EPSILON)
604 gtk_adjustment_set_value (progress->adjustment, value);
608 gtk_progress_get_value (GtkProgress *progress)
610 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
612 return progress->adjustment ? progress->adjustment->value : 0;
616 gtk_progress_set_show_text (GtkProgress *progress,
619 g_return_if_fail (GTK_IS_PROGRESS (progress));
621 if (progress->show_text != show_text)
623 progress->show_text = show_text;
625 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
626 gtk_widget_queue_resize (GTK_WIDGET (progress));
628 g_object_notify (G_OBJECT (progress), "show_text");
633 gtk_progress_set_text_alignment (GtkProgress *progress,
637 g_return_if_fail (GTK_IS_PROGRESS (progress));
638 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
639 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
641 if (progress->x_align != x_align || progress->y_align != y_align)
643 g_object_freeze_notify (G_OBJECT (progress));
644 if (progress->x_align != x_align)
646 progress->x_align = x_align;
647 g_object_notify (G_OBJECT (progress), "text_xalign");
650 if (progress->y_align != y_align)
652 progress->y_align = y_align;
653 g_object_notify (G_OBJECT (progress), "text_yalign");
655 g_object_thaw_notify (G_OBJECT (progress));
657 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
658 gtk_widget_queue_resize (GTK_WIDGET (progress));
663 gtk_progress_set_format_string (GtkProgress *progress,
668 g_return_if_fail (GTK_IS_PROGRESS (progress));
670 /* Turn on format, in case someone called
671 * gtk_progress_bar_set_text() and turned it off.
673 progress->use_text_format = TRUE;
675 old_format = progress->format;
678 format = DEFAULT_FORMAT;
680 progress->format = g_strdup (format);
683 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
684 gtk_widget_queue_resize (GTK_WIDGET (progress));
688 gtk_progress_get_current_text (GtkProgress *progress)
690 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
692 if (!progress->adjustment)
693 gtk_progress_set_adjustment (progress, NULL);
695 return gtk_progress_build_string (progress, progress->adjustment->value,
696 gtk_progress_get_current_percentage (progress));
700 gtk_progress_get_text_from_value (GtkProgress *progress,
703 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
705 if (!progress->adjustment)
706 gtk_progress_set_adjustment (progress, NULL);
708 return gtk_progress_build_string (progress, value,
709 gtk_progress_get_percentage_from_value (progress, value));
713 gtk_progress_set_activity_mode (GtkProgress *progress,
714 gboolean activity_mode)
716 g_return_if_fail (GTK_IS_PROGRESS (progress));
718 if (progress->activity_mode != (activity_mode != FALSE))
720 progress->activity_mode = (activity_mode != FALSE);
722 if (progress->activity_mode)
723 GTK_PROGRESS_GET_CLASS (progress)->act_mode_enter (progress);
725 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
726 gtk_widget_queue_resize (GTK_WIDGET (progress));
728 g_object_notify (G_OBJECT (progress), "activity_mode");