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/.
28 #include <glib/gprintf.h>
31 #include "gtkprogress.h"
32 #include "gtkprivate.h"
37 #define DEFAULT_FORMAT "%P %%"
48 static void gtk_progress_class_init (GtkProgressClass *klass);
49 static void gtk_progress_init (GtkProgress *progress);
50 static void gtk_progress_set_property (GObject *object,
54 static void gtk_progress_get_property (GObject *object,
58 static void gtk_progress_destroy (GtkObject *object);
59 static void gtk_progress_finalize (GObject *object);
60 static void gtk_progress_realize (GtkWidget *widget);
61 static gint gtk_progress_expose (GtkWidget *widget,
62 GdkEventExpose *event);
63 static void gtk_progress_size_allocate (GtkWidget *widget,
64 GtkAllocation *allocation);
65 static void gtk_progress_create_pixmap (GtkProgress *progress);
66 static void gtk_progress_value_changed (GtkAdjustment *adjustment,
67 GtkProgress *progress);
68 static void gtk_progress_changed (GtkAdjustment *adjustment,
69 GtkProgress *progress);
72 static GtkWidgetClass *parent_class = NULL;
76 gtk_progress_get_type (void)
78 static GType progress_type = 0;
82 static const GTypeInfo progress_info =
84 sizeof (GtkProgressClass),
86 NULL, /* base_finalize */
87 (GClassInitFunc) gtk_progress_class_init,
88 NULL, /* class_finalize */
89 NULL, /* class_data */
92 (GInstanceInitFunc) gtk_progress_init,
95 progress_type = g_type_register_static (GTK_TYPE_WIDGET, "GtkProgress",
103 gtk_progress_class_init (GtkProgressClass *class)
105 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
106 GtkObjectClass *object_class;
107 GtkWidgetClass *widget_class;
109 object_class = (GtkObjectClass *) class;
110 widget_class = (GtkWidgetClass *) class;
112 parent_class = gtk_type_class (GTK_TYPE_WIDGET);
114 gobject_class->finalize = gtk_progress_finalize;
116 gobject_class->set_property = gtk_progress_set_property;
117 gobject_class->get_property = gtk_progress_get_property;
118 object_class->destroy = gtk_progress_destroy;
120 widget_class->realize = gtk_progress_realize;
121 widget_class->expose_event = gtk_progress_expose;
122 widget_class->size_allocate = gtk_progress_size_allocate;
124 /* to be overridden */
126 class->update = NULL;
127 class->act_mode_enter = NULL;
129 g_object_class_install_property (gobject_class,
131 g_param_spec_boolean ("activity-mode",
133 P_("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"),
135 GTK_PARAM_READWRITE));
137 g_object_class_install_property (gobject_class,
139 g_param_spec_boolean ("show-text",
141 P_("Whether the progress is shown as text"),
143 GTK_PARAM_READWRITE));
145 g_object_class_install_property (gobject_class,
147 g_param_spec_float ("text-xalign",
148 P_("Text x alignment"),
149 P_("A number between 0.0 and 1.0 specifying the horizontal alignment of the text in the progress widget"),
153 GTK_PARAM_READWRITE));
154 g_object_class_install_property (gobject_class,
156 g_param_spec_float ("text-yalign",
157 P_("Text y alignment"),
158 P_("A number between 0.0 and 1.0 specifying the vertical alignment of the text in the progress widget"),
162 GTK_PARAM_READWRITE));
166 gtk_progress_set_property (GObject *object,
171 GtkProgress *progress;
173 progress = GTK_PROGRESS (object);
177 case PROP_ACTIVITY_MODE:
178 gtk_progress_set_activity_mode (progress, g_value_get_boolean (value));
181 gtk_progress_set_show_text (progress, g_value_get_boolean (value));
183 case PROP_TEXT_XALIGN:
184 gtk_progress_set_text_alignment (progress,
185 g_value_get_float (value),
188 case PROP_TEXT_YALIGN:
189 gtk_progress_set_text_alignment (progress,
191 g_value_get_float (value));
194 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
200 gtk_progress_get_property (GObject *object,
205 GtkProgress *progress;
207 progress = GTK_PROGRESS (object);
211 case PROP_ACTIVITY_MODE:
212 g_value_set_boolean (value, (progress->activity_mode != FALSE));
215 g_value_set_boolean (value, (progress->show_text != FALSE));
217 case PROP_TEXT_XALIGN:
218 g_value_set_float (value, progress->x_align);
220 case PROP_TEXT_YALIGN:
221 g_value_set_float (value, progress->y_align);
224 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
230 gtk_progress_init (GtkProgress *progress)
232 progress->adjustment = NULL;
233 progress->offscreen_pixmap = NULL;
234 progress->format = g_strdup (DEFAULT_FORMAT);
235 progress->x_align = 0.5;
236 progress->y_align = 0.5;
237 progress->show_text = FALSE;
238 progress->activity_mode = FALSE;
239 progress->use_text_format = TRUE;
243 gtk_progress_realize (GtkWidget *widget)
245 GtkProgress *progress;
246 GdkWindowAttr attributes;
247 gint attributes_mask;
249 g_return_if_fail (GTK_IS_PROGRESS (widget));
251 progress = GTK_PROGRESS (widget);
252 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
254 attributes.window_type = GDK_WINDOW_CHILD;
255 attributes.x = widget->allocation.x;
256 attributes.y = widget->allocation.y;
257 attributes.width = widget->allocation.width;
258 attributes.height = widget->allocation.height;
259 attributes.wclass = GDK_INPUT_OUTPUT;
260 attributes.visual = gtk_widget_get_visual (widget);
261 attributes.colormap = gtk_widget_get_colormap (widget);
262 attributes.event_mask = gtk_widget_get_events (widget);
263 attributes.event_mask |= GDK_EXPOSURE_MASK;
265 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
267 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
268 &attributes, attributes_mask);
269 gdk_window_set_user_data (widget->window, progress);
271 widget->style = gtk_style_attach (widget->style, widget->window);
272 gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
274 gtk_progress_create_pixmap (progress);
278 gtk_progress_destroy (GtkObject *object)
280 GtkProgress *progress;
282 g_return_if_fail (GTK_IS_PROGRESS (object));
284 progress = GTK_PROGRESS (object);
286 if (progress->adjustment)
288 g_signal_handlers_disconnect_by_func (progress->adjustment,
289 gtk_progress_value_changed,
291 g_signal_handlers_disconnect_by_func (progress->adjustment,
292 gtk_progress_changed,
294 g_object_unref (progress->adjustment);
295 progress->adjustment = NULL;
298 GTK_OBJECT_CLASS (parent_class)->destroy (object);
302 gtk_progress_finalize (GObject *object)
304 GtkProgress *progress;
306 g_return_if_fail (GTK_IS_PROGRESS (object));
308 progress = GTK_PROGRESS (object);
310 if (progress->offscreen_pixmap)
311 g_object_unref (progress->offscreen_pixmap);
313 if (progress->format)
314 g_free (progress->format);
316 G_OBJECT_CLASS (parent_class)->finalize (object);
320 gtk_progress_expose (GtkWidget *widget,
321 GdkEventExpose *event)
323 g_return_val_if_fail (GTK_IS_PROGRESS (widget), FALSE);
324 g_return_val_if_fail (event != NULL, FALSE);
326 if (GTK_WIDGET_DRAWABLE (widget))
327 gdk_draw_drawable (widget->window,
328 widget->style->black_gc,
329 GTK_PROGRESS (widget)->offscreen_pixmap,
330 event->area.x, event->area.y,
331 event->area.x, event->area.y,
339 gtk_progress_size_allocate (GtkWidget *widget,
340 GtkAllocation *allocation)
342 g_return_if_fail (GTK_IS_PROGRESS (widget));
343 g_return_if_fail (allocation != NULL);
345 widget->allocation = *allocation;
347 if (GTK_WIDGET_REALIZED (widget))
349 gdk_window_move_resize (widget->window,
350 allocation->x, allocation->y,
351 allocation->width, allocation->height);
353 gtk_progress_create_pixmap (GTK_PROGRESS (widget));
358 gtk_progress_create_pixmap (GtkProgress *progress)
362 g_return_if_fail (GTK_IS_PROGRESS (progress));
364 if (GTK_WIDGET_REALIZED (progress))
366 widget = GTK_WIDGET (progress);
368 if (progress->offscreen_pixmap)
369 g_object_unref (progress->offscreen_pixmap);
371 progress->offscreen_pixmap = gdk_pixmap_new (widget->window,
372 widget->allocation.width,
373 widget->allocation.height,
375 GTK_PROGRESS_GET_CLASS (progress)->paint (progress);
380 gtk_progress_changed (GtkAdjustment *adjustment,
381 GtkProgress *progress)
383 /* A change in the value of adjustment->upper can change
386 if (progress->use_text_format && progress->show_text)
387 gtk_widget_queue_resize (GTK_WIDGET (progress));
389 GTK_PROGRESS_GET_CLASS (progress)->update (progress);
393 gtk_progress_value_changed (GtkAdjustment *adjustment,
394 GtkProgress *progress)
396 GTK_PROGRESS_GET_CLASS (progress)->update (progress);
400 gtk_progress_build_string (GtkProgress *progress,
404 gchar buf[256] = { 0 };
405 gchar tmp[256] = { 0 };
410 src = progress->format;
412 /* This is the new supported version of this function */
413 if (!progress->use_text_format)
414 return g_strdup (src);
416 /* And here's all the deprecated goo. */
432 c = *(src + sizeof(gchar));
435 if (c >= '0' && c <= '2')
437 digits = (gint) (c - '0');
439 c = *(src + sizeof(gchar));
453 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
454 g_snprintf (tmp, sizeof (tmp), fmt, 100 * percentage);
457 g_snprintf (tmp, sizeof (tmp), "%.0f", 100 * percentage);
459 dest = &(buf[strlen (buf)]);
466 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
467 g_snprintf (tmp, sizeof (tmp), fmt, value);
470 g_snprintf (tmp, sizeof (tmp), "%.0f", value);
472 dest = &(buf[strlen (buf)]);
479 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
480 g_snprintf (tmp, sizeof (tmp), fmt, progress->adjustment->lower);
483 g_snprintf (tmp, sizeof (tmp), "%.0f", progress->adjustment->lower);
485 dest = &(buf[strlen (buf)]);
492 g_snprintf (fmt, sizeof (fmt), "%%.%df", digits);
493 g_snprintf (tmp, sizeof (tmp), fmt, progress->adjustment->upper);
496 g_snprintf (tmp, sizeof (tmp), "%.0f", progress->adjustment->upper);
498 dest = &(buf[strlen (buf)]);
508 return g_strdup (buf);
511 /***************************************************************/
514 gtk_progress_set_adjustment (GtkProgress *progress,
515 GtkAdjustment *adjustment)
517 g_return_if_fail (GTK_IS_PROGRESS (progress));
519 g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
521 adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 100, 0, 0, 0);
523 if (progress->adjustment != adjustment)
525 if (progress->adjustment)
527 g_signal_handlers_disconnect_by_func (progress->adjustment,
528 gtk_progress_changed,
530 g_signal_handlers_disconnect_by_func (progress->adjustment,
531 gtk_progress_value_changed,
533 g_object_unref (progress->adjustment);
535 progress->adjustment = adjustment;
538 g_object_ref (adjustment);
539 gtk_object_sink (GTK_OBJECT (adjustment));
540 g_signal_connect (adjustment, "changed",
541 G_CALLBACK (gtk_progress_changed),
543 g_signal_connect (adjustment, "value_changed",
544 G_CALLBACK (gtk_progress_value_changed),
548 gtk_progress_changed (adjustment, progress);
553 gtk_progress_configure (GtkProgress *progress,
559 gboolean changed = FALSE;
561 g_return_if_fail (GTK_IS_PROGRESS (progress));
562 g_return_if_fail (min <= max);
563 g_return_if_fail (value >= min && value <= max);
565 if (!progress->adjustment)
566 gtk_progress_set_adjustment (progress, NULL);
567 adj = progress->adjustment;
569 if (fabs (adj->lower - min) > EPSILON || fabs (adj->upper - max) > EPSILON)
576 gtk_adjustment_value_changed (adj);
578 gtk_adjustment_changed (adj);
582 gtk_progress_set_percentage (GtkProgress *progress,
585 g_return_if_fail (GTK_IS_PROGRESS (progress));
586 g_return_if_fail (percentage >= 0 && percentage <= 1.0);
588 if (!progress->adjustment)
589 gtk_progress_set_adjustment (progress, NULL);
590 gtk_progress_set_value (progress, progress->adjustment->lower + percentage *
591 (progress->adjustment->upper - progress->adjustment->lower));
595 gtk_progress_get_current_percentage (GtkProgress *progress)
597 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
599 if (!progress->adjustment)
600 gtk_progress_set_adjustment (progress, NULL);
602 return gtk_progress_get_percentage_from_value (progress, progress->adjustment->value);
606 gtk_progress_get_percentage_from_value (GtkProgress *progress,
609 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
611 if (!progress->adjustment)
612 gtk_progress_set_adjustment (progress, NULL);
614 if (progress->adjustment->lower < progress->adjustment->upper &&
615 value >= progress->adjustment->lower &&
616 value <= progress->adjustment->upper)
617 return (value - progress->adjustment->lower) /
618 (progress->adjustment->upper - progress->adjustment->lower);
624 gtk_progress_set_value (GtkProgress *progress,
627 g_return_if_fail (GTK_IS_PROGRESS (progress));
629 if (!progress->adjustment)
630 gtk_progress_set_adjustment (progress, NULL);
632 if (fabs (progress->adjustment->value - value) > EPSILON)
633 gtk_adjustment_set_value (progress->adjustment, value);
637 gtk_progress_get_value (GtkProgress *progress)
639 g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
641 return progress->adjustment ? progress->adjustment->value : 0;
645 gtk_progress_set_show_text (GtkProgress *progress,
648 g_return_if_fail (GTK_IS_PROGRESS (progress));
650 if (progress->show_text != show_text)
652 progress->show_text = show_text;
654 gtk_widget_queue_resize (GTK_WIDGET (progress));
656 g_object_notify (G_OBJECT (progress), "show_text");
661 gtk_progress_set_text_alignment (GtkProgress *progress,
665 g_return_if_fail (GTK_IS_PROGRESS (progress));
666 g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
667 g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
669 if (progress->x_align != x_align || progress->y_align != y_align)
671 g_object_freeze_notify (G_OBJECT (progress));
672 if (progress->x_align != x_align)
674 progress->x_align = x_align;
675 g_object_notify (G_OBJECT (progress), "text_xalign");
678 if (progress->y_align != y_align)
680 progress->y_align = y_align;
681 g_object_notify (G_OBJECT (progress), "text_yalign");
683 g_object_thaw_notify (G_OBJECT (progress));
685 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
686 gtk_widget_queue_resize (GTK_WIDGET (progress));
691 gtk_progress_set_format_string (GtkProgress *progress,
696 g_return_if_fail (GTK_IS_PROGRESS (progress));
698 /* Turn on format, in case someone called
699 * gtk_progress_bar_set_text() and turned it off.
701 progress->use_text_format = TRUE;
703 old_format = progress->format;
706 format = DEFAULT_FORMAT;
708 progress->format = g_strdup (format);
711 gtk_widget_queue_resize (GTK_WIDGET (progress));
715 gtk_progress_get_current_text (GtkProgress *progress)
717 g_return_val_if_fail (GTK_IS_PROGRESS (progress), NULL);
719 if (!progress->adjustment)
720 gtk_progress_set_adjustment (progress, NULL);
722 return gtk_progress_build_string (progress, progress->adjustment->value,
723 gtk_progress_get_current_percentage (progress));
727 gtk_progress_get_text_from_value (GtkProgress *progress,
730 g_return_val_if_fail (GTK_IS_PROGRESS (progress), NULL);
732 if (!progress->adjustment)
733 gtk_progress_set_adjustment (progress, NULL);
735 return gtk_progress_build_string (progress, value,
736 gtk_progress_get_percentage_from_value (progress, value));
740 gtk_progress_set_activity_mode (GtkProgress *progress,
741 gboolean activity_mode)
743 g_return_if_fail (GTK_IS_PROGRESS (progress));
745 if (progress->activity_mode != (activity_mode != FALSE))
747 progress->activity_mode = (activity_mode != FALSE);
749 if (progress->activity_mode)
750 GTK_PROGRESS_GET_CLASS (progress)->act_mode_enter (progress);
752 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
753 gtk_widget_queue_resize (GTK_WIDGET (progress));
755 g_object_notify (G_OBJECT (progress), "activity_mode");
759 #define __GTK_PROGRESS_C__
760 #include "gtkaliasdef.c"