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/.
30 #include "gtkprogress.h"
31 #include "gtksignal.h"
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);
65 static GtkWidgetClass *parent_class = NULL;
69 gtk_progress_get_type (void)
71 static GtkType progress_type = 0;
75 static const GtkTypeInfo progress_info =
79 sizeof (GtkProgressClass),
80 (GtkClassInitFunc) gtk_progress_class_init,
81 (GtkObjectInitFunc) gtk_progress_init,
82 /* reserved_1 */ NULL,
83 /* reserved_2 */ NULL,
84 (GtkClassInitFunc) NULL
87 progress_type = gtk_type_unique (GTK_TYPE_WIDGET, &progress_info);
94 gtk_progress_class_init (GtkProgressClass *class)
96 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
97 GtkObjectClass *object_class;
98 GtkWidgetClass *widget_class;
100 object_class = (GtkObjectClass *) class;
101 widget_class = (GtkWidgetClass *) class;
102 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
104 gobject_class->finalize = gtk_progress_finalize;
106 gobject_class->set_property = gtk_progress_set_property;
107 gobject_class->get_property = gtk_progress_get_property;
108 object_class->destroy = gtk_progress_destroy;
110 widget_class->realize = gtk_progress_realize;
111 widget_class->expose_event = gtk_progress_expose;
112 widget_class->size_allocate = gtk_progress_size_allocate;
114 /* to be overridden */
116 class->update = NULL;
117 class->act_mode_enter = NULL;
119 g_object_class_install_property (gobject_class,
121 g_param_spec_boolean ("activity_mode",
123 _("If true the GtkProgress is in activity mode, meaning that is 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."),
127 g_object_class_install_property (gobject_class,
129 g_param_spec_boolean ("show_text",
131 _("Whether the progress is shown as text"),
135 g_object_class_install_property (gobject_class,
137 g_param_spec_float ("text_xalign",
138 _("Text x alignment"),
139 _("A number between 0.0 and 1.0 specifying the horizontal alignment of the text in the progresswidget"),
144 g_object_class_install_property (gobject_class,
146 g_param_spec_float ("text_yalign",
147 _("Text y alignment"),
148 _("A number between 0.0 and 1.0 specifying the vertical alignment of the text in the progress widget"),
156 gtk_progress_set_property (GObject *object,
161 GtkProgress *progress;
163 progress = GTK_PROGRESS (object);
167 case PROP_ACTIVITY_MODE:
168 gtk_progress_set_activity_mode (progress, g_value_get_boolean (value));
171 gtk_progress_set_show_text (progress, g_value_get_boolean (value));
173 case PROP_TEXT_XALIGN:
174 gtk_progress_set_text_alignment (progress,
175 g_value_get_float (value),
178 case PROP_TEXT_YALIGN:
179 gtk_progress_set_text_alignment (progress,
181 g_value_get_float (value));
184 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
190 gtk_progress_get_property (GObject *object,
195 GtkProgress *progress;
197 progress = GTK_PROGRESS (object);
201 case PROP_ACTIVITY_MODE:
202 g_value_set_boolean (value, (progress->activity_mode != FALSE));
205 g_value_set_boolean (value, (progress->show_text != FALSE));
207 case PROP_TEXT_XALIGN:
208 g_value_set_float (value, progress->x_align);
210 case PROP_TEXT_YALIGN:
211 g_value_set_float (value, progress->y_align);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
220 gtk_progress_init (GtkProgress *progress)
222 progress->adjustment = NULL;
223 progress->offscreen_pixmap = NULL;
224 progress->format = g_strdup ("%P %%");
225 progress->x_align = 0.5;
226 progress->y_align = 0.5;
227 progress->show_text = FALSE;
228 progress->activity_mode = FALSE;
229 progress->use_text_format = TRUE;
233 gtk_progress_realize (GtkWidget *widget)
235 GtkProgress *progress;
236 GdkWindowAttr attributes;
237 gint attributes_mask;
239 g_return_if_fail (GTK_IS_PROGRESS (widget));
241 progress = GTK_PROGRESS (widget);
242 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
244 attributes.window_type = GDK_WINDOW_CHILD;
245 attributes.x = widget->allocation.x;
246 attributes.y = widget->allocation.y;
247 attributes.width = widget->allocation.width;
248 attributes.height = widget->allocation.height;
249 attributes.wclass = GDK_INPUT_OUTPUT;
250 attributes.visual = gtk_widget_get_visual (widget);
251 attributes.colormap = gtk_widget_get_colormap (widget);
252 attributes.event_mask = gtk_widget_get_events (widget);
253 attributes.event_mask |= GDK_EXPOSURE_MASK;
255 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
257 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
258 &attributes, attributes_mask);
259 gdk_window_set_user_data (widget->window, progress);
261 widget->style = gtk_style_attach (widget->style, widget->window);
262 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
264 gtk_progress_create_pixmap (progress);
268 gtk_progress_destroy (GtkObject *object)
270 GtkProgress *progress;
272 g_return_if_fail (GTK_IS_PROGRESS (object));
274 progress = GTK_PROGRESS (object);
276 if (progress->adjustment)
278 gtk_signal_disconnect_by_data (GTK_OBJECT (progress->adjustment),
280 gtk_object_unref (GTK_OBJECT (progress->adjustment));
281 progress->adjustment = NULL;
284 GTK_OBJECT_CLASS (parent_class)->destroy (object);
288 gtk_progress_finalize (GObject *object)
290 GtkProgress *progress;
292 g_return_if_fail (GTK_IS_PROGRESS (object));
294 progress = GTK_PROGRESS (object);
296 if (progress->offscreen_pixmap)
297 gdk_pixmap_unref (progress->offscreen_pixmap);
299 if (progress->format)
300 g_free (progress->format);
302 G_OBJECT_CLASS (parent_class)->finalize (object);
306 gtk_progress_expose (GtkWidget *widget,
307 GdkEventExpose *event)
309 g_return_val_if_fail (GTK_IS_PROGRESS (widget), FALSE);
310 g_return_val_if_fail (event != NULL, FALSE);
312 if (GTK_WIDGET_DRAWABLE (widget))
313 gdk_draw_pixmap (widget->window,
314 widget->style->black_gc,
315 GTK_PROGRESS (widget)->offscreen_pixmap,
316 event->area.x, event->area.y,
317 event->area.x, event->area.y,
325 gtk_progress_size_allocate (GtkWidget *widget,
326 GtkAllocation *allocation)
328 g_return_if_fail (GTK_IS_PROGRESS (widget));
329 g_return_if_fail (allocation != NULL);
331 widget->allocation = *allocation;
333 if (GTK_WIDGET_REALIZED (widget))
335 gdk_window_move_resize (widget->window,
336 allocation->x, allocation->y,
337 allocation->width, allocation->height);
339 gtk_progress_create_pixmap (GTK_PROGRESS (widget));
344 gtk_progress_create_pixmap (GtkProgress *progress)
348 g_return_if_fail (GTK_IS_PROGRESS (progress));
350 if (GTK_WIDGET_REALIZED (progress))
352 widget = GTK_WIDGET (progress);
354 if (progress->offscreen_pixmap)
355 gdk_pixmap_unref (progress->offscreen_pixmap);
357 progress->offscreen_pixmap = gdk_pixmap_new (widget->window,
358 widget->allocation.width,
359 widget->allocation.height,
361 GTK_PROGRESS_GET_CLASS (progress)->paint (progress);
366 gtk_progress_value_changed (GtkAdjustment *adjustment,
367 GtkProgress *progress)
369 GTK_PROGRESS_GET_CLASS (progress)->update (progress);
373 gtk_progress_build_string (GtkProgress *progress,
377 gchar buf[256] = { 0 };
378 gchar tmp[256] = { 0 };
383 src = progress->format;
385 /* This is the new supported version of this function */
386 if (!progress->use_text_format)
387 return g_strdup (src);
389 /* And here's all the deprecated goo. */
405 c = *(src + sizeof(gchar));
408 if (c >= '0' && c <= '2')
410 digits = (gint) (c - '0');
412 c = *(src + sizeof(gchar));
426 sprintf (fmt, "%%.%df", digits);
427 sprintf (tmp, fmt, 100 * percentage);
430 sprintf (tmp, "%.0f", 100 * percentage);
432 dest = &(buf[strlen (buf)]);
439 sprintf (fmt, "%%.%df", digits);
440 sprintf (tmp, fmt, value);
443 sprintf (tmp, "%.0f", value);
445 dest = &(buf[strlen (buf)]);
452 sprintf (fmt, "%%.%df", digits);
453 sprintf (tmp, fmt, progress->adjustment->lower);
456 sprintf (tmp, "%.0f", progress->adjustment->lower);
458 dest = &(buf[strlen (buf)]);
465 sprintf (fmt, "%%.%df", digits);
466 sprintf (tmp, fmt, progress->adjustment->upper);
469 sprintf (tmp, "%.0f", progress->adjustment->upper);
471 dest = &(buf[strlen (buf)]);
481 return g_strdup (buf);
484 /***************************************************************/
487 gtk_progress_set_adjustment (GtkProgress *progress,
488 GtkAdjustment *adjustment)
490 g_return_if_fail (GTK_IS_PROGRESS (progress));
492 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
494 adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 100, 0, 0, 0);
496 if (progress->adjustment != adjustment)
498 if (progress->adjustment)
500 gtk_signal_disconnect_by_data (GTK_OBJECT (progress->adjustment),
501 (gpointer) progress);
502 gtk_object_unref (GTK_OBJECT (progress->adjustment));
504 progress->adjustment = adjustment;
507 gtk_object_ref (GTK_OBJECT (adjustment));
508 gtk_object_sink (GTK_OBJECT (adjustment));
509 gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
510 (GtkSignalFunc) gtk_progress_value_changed,
511 (gpointer) progress);
517 gtk_progress_configure (GtkProgress *progress,
523 gboolean changed = FALSE;
525 g_return_if_fail (GTK_IS_PROGRESS (progress));
526 g_return_if_fail (min <= max);
527 g_return_if_fail (value >= min && value <= max);
529 if (!progress->adjustment)
530 gtk_progress_set_adjustment (progress, NULL);
531 adj = progress->adjustment;
533 if (fabs (adj->lower - min) > EPSILON || fabs (adj->upper - max) > EPSILON)
540 gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
542 gtk_signal_emit_by_name (GTK_OBJECT (progress->adjustment), "changed");
546 gtk_progress_set_percentage (GtkProgress *progress,
549 g_return_if_fail (GTK_IS_PROGRESS (progress));
550 g_return_if_fail (percentage >= 0 && percentage <= 1.0);
552 if (!progress->adjustment)
553 gtk_progress_set_adjustment (progress, NULL);
554 gtk_progress_set_value (progress, progress->adjustment->lower + percentage *
555 (progress->adjustment->upper - progress->adjustment->lower));
559 gtk_progress_get_current_percentage (GtkProgress *progress)
561 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
563 if (!progress->adjustment)
564 gtk_progress_set_adjustment (progress, NULL);
566 return ((progress->adjustment->value - progress->adjustment->lower) /
567 (progress->adjustment->upper - progress->adjustment->lower));
571 gtk_progress_get_percentage_from_value (GtkProgress *progress,
574 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
576 if (!progress->adjustment)
577 gtk_progress_set_adjustment (progress, NULL);
579 if (value >= progress->adjustment->lower &&
580 value <= progress->adjustment->upper)
581 return (value - progress->adjustment->lower) /
582 (progress->adjustment->upper - progress->adjustment->lower);
588 gtk_progress_set_value (GtkProgress *progress,
591 g_return_if_fail (GTK_IS_PROGRESS (progress));
593 if (!progress->adjustment)
594 gtk_progress_set_adjustment (progress, NULL);
596 if (fabs (progress->adjustment->value - value) > EPSILON)
597 gtk_adjustment_set_value (progress->adjustment, value);
601 gtk_progress_get_value (GtkProgress *progress)
603 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
605 return progress->adjustment ? progress->adjustment->value : 0;
609 gtk_progress_set_show_text (GtkProgress *progress,
612 g_return_if_fail (GTK_IS_PROGRESS (progress));
614 if (progress->show_text != show_text)
616 progress->show_text = show_text;
618 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
619 gtk_widget_queue_resize (GTK_WIDGET (progress));
621 g_object_notify (G_OBJECT (progress), "show_text");
626 gtk_progress_set_text_alignment (GtkProgress *progress,
630 g_return_if_fail (GTK_IS_PROGRESS (progress));
631 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
632 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
634 if (progress->x_align != x_align || progress->y_align != y_align)
636 g_object_freeze_notify (G_OBJECT (progress));
637 if (progress->x_align != x_align)
639 progress->x_align = x_align;
640 g_object_notify (G_OBJECT (progress), "text_xalign");
643 if (progress->y_align != y_align)
645 progress->y_align = y_align;
646 g_object_notify (G_OBJECT (progress), "text_yalign");
648 g_object_thaw_notify (G_OBJECT (progress));
650 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
651 gtk_widget_queue_resize (GTK_WIDGET (progress));
656 gtk_progress_set_format_string (GtkProgress *progress,
659 g_return_if_fail (GTK_IS_PROGRESS (progress));
661 /* Turn on format, in case someone called
662 * gtk_progress_bar_set_text() and turned it off.
664 progress->use_text_format = TRUE;
668 if (progress->format)
669 g_free (progress->format);
670 progress->format = g_strdup (format);
672 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
673 gtk_widget_queue_resize (GTK_WIDGET (progress));
678 gtk_progress_get_current_text (GtkProgress *progress)
680 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
682 if (!progress->adjustment)
683 gtk_progress_set_adjustment (progress, NULL);
685 return gtk_progress_build_string (progress, progress->adjustment->value,
686 gtk_progress_get_current_percentage (progress));
690 gtk_progress_get_text_from_value (GtkProgress *progress,
693 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
695 if (!progress->adjustment)
696 gtk_progress_set_adjustment (progress, NULL);
698 return gtk_progress_build_string (progress, value,
699 gtk_progress_get_percentage_from_value (progress, value));
703 gtk_progress_set_activity_mode (GtkProgress *progress,
704 gboolean activity_mode)
706 g_return_if_fail (GTK_IS_PROGRESS (progress));
708 if (progress->activity_mode != (activity_mode != FALSE))
710 progress->activity_mode = (activity_mode != FALSE);
712 if (progress->activity_mode)
713 GTK_PROGRESS_GET_CLASS (progress)->act_mode_enter (progress);
715 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
716 gtk_widget_queue_resize (GTK_WIDGET (progress));
718 g_object_notify (G_OBJECT (progress), "activity_mode");