]> Pileus Git - ~andy/gtk/blob - gtk/gtkprogressbar.c
295f4143a1244c80f980f173bd497bb3a4fb925f
[~andy/gtk] / gtk / gtkprogressbar.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #if HAVE_CONFIG_H
28 #  include <config.h>
29 #  if STDC_HEADERS
30 #    include <string.h>
31 #    include <stdio.h>
32 #  endif
33 #else
34 #  include <stdio.h>
35 #endif
36
37 #include "gtkprogressbar.h"
38 #include "gtkprivate.h"
39 #include "gtkintl.h"
40 #include "gtkalias.h"
41
42
43 #define MIN_HORIZONTAL_BAR_WIDTH   150
44 #define MIN_HORIZONTAL_BAR_HEIGHT  20
45 #define MIN_VERTICAL_BAR_WIDTH     22
46 #define MIN_VERTICAL_BAR_HEIGHT    80
47 #define MAX_TEXT_LENGTH            80
48
49 enum {
50   PROP_0,
51
52   /* Supported args */
53   PROP_FRACTION,
54   PROP_PULSE_STEP,
55   PROP_ORIENTATION,
56   PROP_TEXT,
57   PROP_ELLIPSIZE,
58   
59   /* Deprecated args */
60   PROP_ADJUSTMENT,
61   PROP_BAR_STYLE,
62   PROP_ACTIVITY_STEP,
63   PROP_ACTIVITY_BLOCKS,
64   PROP_DISCRETE_BLOCKS
65 };
66
67 static void gtk_progress_bar_set_property  (GObject             *object,
68                                             guint                prop_id,
69                                             const GValue        *value,
70                                             GParamSpec          *pspec);
71 static void gtk_progress_bar_get_property  (GObject             *object,
72                                             guint                prop_id,
73                                             GValue              *value,
74                                             GParamSpec          *pspec);
75 static gboolean gtk_progress_bar_expose    (GtkWidget           *widget,
76                                             GdkEventExpose      *event);
77 static void gtk_progress_bar_size_request  (GtkWidget           *widget,
78                                             GtkRequisition      *requisition);
79 static void gtk_progress_bar_real_update   (GtkProgress         *progress);
80 static void gtk_progress_bar_paint         (GtkProgress         *progress);
81 static void gtk_progress_bar_act_mode_enter (GtkProgress        *progress);
82
83 static void gtk_progress_bar_set_bar_style_internal       (GtkProgressBar *pbar,
84                                                            GtkProgressBarStyle style);
85 static void gtk_progress_bar_set_discrete_blocks_internal (GtkProgressBar *pbar,
86                                                            guint           blocks);
87 static void gtk_progress_bar_set_activity_step_internal   (GtkProgressBar *pbar,
88                                                            guint           step);
89 static void gtk_progress_bar_set_activity_blocks_internal (GtkProgressBar *pbar,
90                                                            guint           blocks);
91
92
93 G_DEFINE_TYPE (GtkProgressBar, gtk_progress_bar, GTK_TYPE_PROGRESS)
94
95 static void
96 gtk_progress_bar_class_init (GtkProgressBarClass *class)
97 {
98   GObjectClass *gobject_class;
99   GtkWidgetClass *widget_class;
100   GtkProgressClass *progress_class;
101   
102   gobject_class = G_OBJECT_CLASS (class);
103   widget_class = (GtkWidgetClass *) class;
104   progress_class = (GtkProgressClass *) class;
105
106   gobject_class->set_property = gtk_progress_bar_set_property;
107   gobject_class->get_property = gtk_progress_bar_get_property;
108   
109   widget_class->expose_event = gtk_progress_bar_expose;
110   widget_class->size_request = gtk_progress_bar_size_request;
111
112   progress_class->paint = gtk_progress_bar_paint;
113   progress_class->update = gtk_progress_bar_real_update;
114   progress_class->act_mode_enter = gtk_progress_bar_act_mode_enter;
115
116   g_object_class_install_property (gobject_class,
117                                    PROP_ADJUSTMENT,
118                                    g_param_spec_object ("adjustment",
119                                                         P_("Adjustment"),
120                                                         P_("The GtkAdjustment connected to the progress bar (Deprecated)"),
121                                                         GTK_TYPE_ADJUSTMENT,
122                                                         GTK_PARAM_READWRITE));
123
124   g_object_class_install_property (gobject_class,
125                                    PROP_ORIENTATION,
126                                    g_param_spec_enum ("orientation",
127                                                       P_("Orientation"),
128                                                       P_("Orientation and growth direction of the progress bar"),
129                                                       GTK_TYPE_PROGRESS_BAR_ORIENTATION,
130                                                       GTK_PROGRESS_LEFT_TO_RIGHT,
131                                                       GTK_PARAM_READWRITE));
132
133   g_object_class_install_property (gobject_class,
134                                    PROP_BAR_STYLE,
135                                    g_param_spec_enum ("bar-style",
136                                                       P_("Bar style"),
137                                                       P_("Specifies the visual style of the bar in percentage mode (Deprecated)"),
138                                                       GTK_TYPE_PROGRESS_BAR_STYLE,
139                                                       GTK_PROGRESS_CONTINUOUS,
140                                                       GTK_PARAM_READWRITE));
141
142   g_object_class_install_property (gobject_class,
143                                    PROP_ACTIVITY_STEP,
144                                    g_param_spec_uint ("activity-step",
145                                                       P_("Activity Step"),
146                                                       P_("The increment used for each iteration in activity mode (Deprecated)"),
147                                                       0, G_MAXUINT, 3,
148                                                       GTK_PARAM_READWRITE));
149
150   g_object_class_install_property (gobject_class,
151                                    PROP_ACTIVITY_BLOCKS,
152                                    g_param_spec_uint ("activity-blocks",
153                                                       P_("Activity Blocks"),
154                                                       P_("The number of blocks which can fit in the progress bar area in activity mode (Deprecated)"),
155                                                       2, G_MAXUINT, 5,
156                                                       GTK_PARAM_READWRITE));
157
158   g_object_class_install_property (gobject_class,
159                                    PROP_DISCRETE_BLOCKS,
160                                    g_param_spec_uint ("discrete-blocks",
161                                                       P_("Discrete Blocks"),
162                                                       P_("The number of discrete blocks in a progress bar (when shown in the discrete style)"),
163                                                       2, G_MAXUINT, 10,
164                                                       GTK_PARAM_READWRITE));
165   
166   g_object_class_install_property (gobject_class,
167                                    PROP_FRACTION,
168                                    g_param_spec_double ("fraction",
169                                                         P_("Fraction"),
170                                                         P_("The fraction of total work that has been completed"),
171                                                         0.0, 1.0, 0.0,
172                                                         GTK_PARAM_READWRITE));  
173   
174   g_object_class_install_property (gobject_class,
175                                    PROP_PULSE_STEP,
176                                    g_param_spec_double ("pulse-step",
177                                                         P_("Pulse Step"),
178                                                         P_("The fraction of total progress to move the bouncing block when pulsed"),
179                                                         0.0, 1.0, 0.1,
180                                                         GTK_PARAM_READWRITE));  
181   
182   g_object_class_install_property (gobject_class,
183                                    PROP_TEXT,
184                                    g_param_spec_string ("text",
185                                                         P_("Text"),
186                                                         P_("Text to be displayed in the progress bar"),
187                                                         "%P %%",
188                                                         GTK_PARAM_READWRITE));
189
190   /**
191    * GtkProgressBar:ellipsize:
192    *
193    * The preferred place to ellipsize the string, if the progressbar does 
194    * not have enough room to display the entire string, specified as a 
195    * #PangoEllisizeMode. 
196    *
197    * Note that setting this property to a value other than 
198    * %PANGO_ELLIPSIZE_NONE has the side-effect that the progressbar requests 
199    * only enough space to display the ellipsis "...". Another means to set a 
200    * progressbar's width is gtk_widget_set_size_request().
201    *
202    * Since: 2.6
203    */
204   g_object_class_install_property (gobject_class,
205                                    PROP_ELLIPSIZE,
206                                    g_param_spec_enum ("ellipsize",
207                                                       P_("Ellipsize"),
208                                                       P_("The preferred place to ellipsize the string, if the progress bar "
209                                                          "does not have enough room to display the entire string, if at all."),
210                                                       PANGO_TYPE_ELLIPSIZE_MODE,
211                                                       PANGO_ELLIPSIZE_NONE,
212                                                       GTK_PARAM_READWRITE));
213   gtk_widget_class_install_style_property (widget_class,
214                                            g_param_spec_int ("xspacing",
215                                                              P_("XSpacing"),
216                                                              P_("Extra spacing applied to the width of a progress bar."),
217                                                              0, G_MAXINT, 7,
218                                                              G_PARAM_READWRITE));
219   gtk_widget_class_install_style_property (widget_class,
220                                            g_param_spec_int ("yspacing",
221                                                              "YSpacing",
222                                                              "Extra spacing applied to the height of a progress bar.",
223                                                              0, G_MAXINT, 7,
224                                                              G_PARAM_READWRITE));
225 }
226
227 static void
228 gtk_progress_bar_init (GtkProgressBar *pbar)
229 {
230   pbar->bar_style = GTK_PROGRESS_CONTINUOUS;
231   pbar->blocks = 10;
232   pbar->in_block = -1;
233   pbar->orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
234   pbar->pulse_fraction = 0.1;
235   pbar->activity_pos = 0;
236   pbar->activity_dir = 1;
237   pbar->activity_step = 3;
238   pbar->activity_blocks = 5;
239   pbar->ellipsize = PANGO_ELLIPSIZE_NONE;
240 }
241
242 static void
243 gtk_progress_bar_set_property (GObject      *object,
244                                guint         prop_id,
245                                const GValue *value,
246                                GParamSpec   *pspec)
247 {
248   GtkProgressBar *pbar;
249
250   pbar = GTK_PROGRESS_BAR (object);
251
252   switch (prop_id)
253     {
254     case PROP_ADJUSTMENT:
255       gtk_progress_set_adjustment (GTK_PROGRESS (pbar),
256                                    GTK_ADJUSTMENT (g_value_get_object (value)));
257       break;
258     case PROP_ORIENTATION:
259       gtk_progress_bar_set_orientation (pbar, g_value_get_enum (value));
260       break;
261     case PROP_BAR_STYLE:
262       gtk_progress_bar_set_bar_style_internal (pbar, g_value_get_enum (value));
263       break;
264     case PROP_ACTIVITY_STEP:
265       gtk_progress_bar_set_activity_step_internal (pbar, g_value_get_uint (value));
266       break;
267     case PROP_ACTIVITY_BLOCKS:
268       gtk_progress_bar_set_activity_blocks_internal (pbar, g_value_get_uint (value));
269       break;
270     case PROP_DISCRETE_BLOCKS:
271       gtk_progress_bar_set_discrete_blocks_internal (pbar, g_value_get_uint (value));
272       break;
273     case PROP_FRACTION:
274       gtk_progress_bar_set_fraction (pbar, g_value_get_double (value));
275       break;
276     case PROP_PULSE_STEP:
277       gtk_progress_bar_set_pulse_step (pbar, g_value_get_double (value));
278       break;
279     case PROP_TEXT:
280       gtk_progress_bar_set_text (pbar, g_value_get_string (value));
281       break;
282     case PROP_ELLIPSIZE:
283       gtk_progress_bar_set_ellipsize (pbar, g_value_get_enum (value));
284       break;
285     default:
286       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
287       break;
288     }
289 }
290
291 static void
292 gtk_progress_bar_get_property (GObject      *object,
293                                guint         prop_id,
294                                GValue       *value,
295                                GParamSpec   *pspec)
296 {
297   GtkProgressBar *pbar;
298
299   pbar = GTK_PROGRESS_BAR (object);
300
301   switch (prop_id)
302     {
303     case PROP_ADJUSTMENT:
304       g_value_set_object (value, GTK_PROGRESS (pbar)->adjustment);
305       break;
306     case PROP_ORIENTATION:
307       g_value_set_enum (value, pbar->orientation);
308       break;
309     case PROP_BAR_STYLE:
310       g_value_set_enum (value, pbar->bar_style);
311       break;
312     case PROP_ACTIVITY_STEP:
313       g_value_set_uint (value, pbar->activity_step);
314       break;
315     case PROP_ACTIVITY_BLOCKS:
316       g_value_set_uint (value, pbar->activity_blocks);
317       break;
318     case PROP_DISCRETE_BLOCKS:
319       g_value_set_uint (value, pbar->blocks);
320       break;
321     case PROP_FRACTION:
322       g_value_set_double (value, gtk_progress_get_current_percentage (GTK_PROGRESS (pbar)));
323       break;
324     case PROP_PULSE_STEP:
325       g_value_set_double (value, pbar->pulse_fraction);
326       break;
327     case PROP_TEXT:
328       g_value_set_string (value, gtk_progress_bar_get_text (pbar));
329       break;
330     case PROP_ELLIPSIZE:
331       g_value_set_enum (value, pbar->ellipsize);
332       break;
333     default:
334       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335       break;
336     }
337 }
338
339 GtkWidget*
340 gtk_progress_bar_new (void)
341 {
342   GtkWidget *pbar;
343
344   pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR, NULL);
345
346   return pbar;
347 }
348
349 GtkWidget*
350 gtk_progress_bar_new_with_adjustment (GtkAdjustment *adjustment)
351 {
352   GtkWidget *pbar;
353
354   g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
355
356   pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR,
357                          "adjustment", adjustment,
358                          NULL);
359
360   return pbar;
361 }
362
363 static void
364 gtk_progress_bar_real_update (GtkProgress *progress)
365 {
366   GtkProgressBar *pbar;
367   GtkWidget *widget;
368
369   g_return_if_fail (GTK_IS_PROGRESS (progress));
370
371   pbar = GTK_PROGRESS_BAR (progress);
372   widget = GTK_WIDGET (progress);
373  
374   if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS ||
375       GTK_PROGRESS (pbar)->activity_mode)
376     {
377       if (GTK_PROGRESS (pbar)->activity_mode)
378         {
379           guint size;
380           
381           /* advance the block */
382
383           if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
384               pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
385             {
386               /* Update our activity step. */
387               
388               pbar->activity_step = widget->allocation.width * pbar->pulse_fraction;
389               
390               size = MAX (2, widget->allocation.width / pbar->activity_blocks);
391
392               if (pbar->activity_dir == 0)
393                 {
394                   pbar->activity_pos += pbar->activity_step;
395                   if (pbar->activity_pos + size >=
396                       widget->allocation.width -
397                       widget->style->xthickness)
398                     {
399                       pbar->activity_pos = widget->allocation.width -
400                         widget->style->xthickness - size;
401                       pbar->activity_dir = 1;
402                     }
403                 }
404               else
405                 {
406                   pbar->activity_pos -= pbar->activity_step;
407                   if (pbar->activity_pos <= widget->style->xthickness)
408                     {
409                       pbar->activity_pos = widget->style->xthickness;
410                       pbar->activity_dir = 0;
411                     }
412                 }
413             }
414           else
415             {
416               /* Update our activity step. */
417               
418               pbar->activity_step = widget->allocation.height * pbar->pulse_fraction;
419               
420               size = MAX (2, widget->allocation.height / pbar->activity_blocks);
421
422               if (pbar->activity_dir == 0)
423                 {
424                   pbar->activity_pos += pbar->activity_step;
425                   if (pbar->activity_pos + size >=
426                       widget->allocation.height -
427                       widget->style->ythickness)
428                     {
429                       pbar->activity_pos = widget->allocation.height -
430                         widget->style->ythickness - size;
431                       pbar->activity_dir = 1;
432                     }
433                 }
434               else
435                 {
436                   pbar->activity_pos -= pbar->activity_step;
437                   if (pbar->activity_pos <= widget->style->ythickness)
438                     {
439                       pbar->activity_pos = widget->style->ythickness;
440                       pbar->activity_dir = 0;
441                     }
442                 }
443             }
444         }
445       pbar->dirty = TRUE;
446       gtk_widget_queue_draw (GTK_WIDGET (progress));
447     }
448   else
449     {
450       gint in_block;
451       
452       in_block = -1 + (gint)(gtk_progress_get_current_percentage (progress) *
453                              (gdouble)pbar->blocks);
454       
455       if (pbar->in_block != in_block)
456         {
457           pbar->in_block = in_block;
458           pbar->dirty = TRUE;
459           gtk_widget_queue_draw (GTK_WIDGET (progress));
460         }
461     }
462 }
463
464 static gboolean
465 gtk_progress_bar_expose (GtkWidget      *widget,
466                      GdkEventExpose *event)
467 {
468   GtkProgressBar *pbar;
469
470   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (widget), FALSE);
471
472   pbar = GTK_PROGRESS_BAR (widget);
473
474   if (GTK_WIDGET_DRAWABLE (widget) && pbar->dirty)
475     gtk_progress_bar_paint (GTK_PROGRESS (pbar));
476
477   return GTK_WIDGET_CLASS (gtk_progress_bar_parent_class)->expose_event (widget, event);
478 }
479
480 static void
481 gtk_progress_bar_size_request (GtkWidget      *widget,
482                                GtkRequisition *requisition)
483 {
484   GtkProgress *progress;
485   GtkProgressBar *pbar;
486   gchar *buf;
487   PangoRectangle logical_rect;
488   PangoLayout *layout;
489   gint width, height;
490   gint xspacing, yspacing;
491
492   g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
493   g_return_if_fail (requisition != NULL);
494
495   gtk_widget_style_get (widget,
496                         "xspacing", &xspacing,
497                         "yspacing", &yspacing,
498                         NULL);
499
500   progress = GTK_PROGRESS (widget);
501   pbar = GTK_PROGRESS_BAR (widget);
502
503   width = 2 * widget->style->xthickness + xspacing;
504   height = 2 * widget->style->ythickness + yspacing;
505
506   if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
507     {
508       if (!progress->adjustment)
509         gtk_progress_set_adjustment (progress, NULL);
510
511       buf = gtk_progress_get_text_from_value (progress, progress->adjustment->upper);
512
513       layout = gtk_widget_create_pango_layout (widget, buf);
514
515       pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
516           
517       if (pbar->ellipsize)
518         {
519           PangoContext *context;
520           PangoFontMetrics *metrics;
521           gint char_width;
522           
523           /* The minimum size for ellipsized text is ~ 3 chars */
524           context = pango_layout_get_context (layout);
525           metrics = pango_context_get_metrics (context, widget->style->font_desc, pango_context_get_language (context));
526           
527           char_width = pango_font_metrics_get_approximate_char_width (metrics);
528           pango_font_metrics_unref (metrics);
529           
530           width += PANGO_PIXELS (char_width) * 3;
531         }
532       else
533         width += logical_rect.width;
534       
535       height += logical_rect.height;
536
537       g_object_unref (layout);
538       g_free (buf);
539     }
540   
541   if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
542       pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
543     {
544       requisition->width = MAX (MIN_HORIZONTAL_BAR_WIDTH, width);
545       requisition->height = MAX (MIN_HORIZONTAL_BAR_HEIGHT, height);
546     }
547   else
548     {
549       requisition->width = MAX (MIN_VERTICAL_BAR_WIDTH, width);
550       requisition->height = MAX (MIN_VERTICAL_BAR_HEIGHT, height);
551     }
552 }
553
554 static void
555 gtk_progress_bar_act_mode_enter (GtkProgress *progress)
556 {
557   GtkProgressBar *pbar;
558   GtkWidget *widget;
559   GtkProgressBarOrientation orientation;
560
561   pbar = GTK_PROGRESS_BAR (progress);
562   widget = GTK_WIDGET (progress);
563
564   orientation = pbar->orientation;
565   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
566     {
567       if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
568         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
569       else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
570         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
571     }
572   
573   /* calculate start pos */
574
575   if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
576       orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
577     {
578       if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
579         {
580           pbar->activity_pos = widget->style->xthickness;
581           pbar->activity_dir = 0;
582         }
583       else
584         {
585           pbar->activity_pos = widget->allocation.width - 
586             widget->style->xthickness - (widget->allocation.height - 
587                 widget->style->ythickness * 2);
588           pbar->activity_dir = 1;
589         }
590     }
591   else
592     {
593       if (orientation == GTK_PROGRESS_TOP_TO_BOTTOM)
594         {
595           pbar->activity_pos = widget->style->ythickness;
596           pbar->activity_dir = 0;
597         }
598       else
599         {
600           pbar->activity_pos = widget->allocation.height -
601             widget->style->ythickness - (widget->allocation.width - 
602                 widget->style->xthickness * 2);
603           pbar->activity_dir = 1;
604         }
605     }
606 }
607
608 static void
609 gtk_progress_bar_get_activity (GtkProgressBar            *pbar,
610                                GtkProgressBarOrientation  orientation,
611                                gint                      *offset,
612                                gint                      *amount)
613 {
614   GtkWidget *widget = GTK_WIDGET (pbar);
615
616   *offset = pbar->activity_pos;
617
618   switch (orientation)
619     {
620     case GTK_PROGRESS_LEFT_TO_RIGHT:
621     case GTK_PROGRESS_RIGHT_TO_LEFT:
622       *amount = MAX (2, widget->allocation.width / pbar->activity_blocks);
623       break;
624
625     case GTK_PROGRESS_TOP_TO_BOTTOM:
626     case GTK_PROGRESS_BOTTOM_TO_TOP:
627       *amount = MAX (2, widget->allocation.height / pbar->activity_blocks);
628       break;
629     }
630 }
631
632 static void
633 gtk_progress_bar_paint_activity (GtkProgressBar            *pbar,
634                                  GtkProgressBarOrientation  orientation)
635 {
636   GtkWidget *widget = GTK_WIDGET (pbar);
637   GtkProgress *progress = GTK_PROGRESS (pbar);
638   GdkRectangle area;
639
640   switch (orientation)
641     {
642     case GTK_PROGRESS_LEFT_TO_RIGHT:
643     case GTK_PROGRESS_RIGHT_TO_LEFT:
644       gtk_progress_bar_get_activity (pbar, orientation, &area.x, &area.width);
645       area.y = widget->style->ythickness;
646       area.height = widget->allocation.height - 2 * widget->style->ythickness;
647       break;
648
649     case GTK_PROGRESS_TOP_TO_BOTTOM:
650     case GTK_PROGRESS_BOTTOM_TO_TOP:
651       gtk_progress_bar_get_activity (pbar, orientation, &area.y, &area.height);
652       area.x = widget->style->xthickness;
653       area.width = widget->allocation.width - 2 * widget->style->xthickness;
654       break;
655
656     default:
657       return;
658       break;
659     }
660
661   gtk_paint_box (widget->style,
662                  progress->offscreen_pixmap,
663                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
664                  &area, widget, "bar",
665                  area.x, area.y, area.width, area.height);
666 }
667
668 static void
669 gtk_progress_bar_paint_continuous (GtkProgressBar            *pbar,
670                                    gint                       amount,
671                                    GtkProgressBarOrientation  orientation)
672 {
673   GdkRectangle area;
674   GtkWidget *widget = GTK_WIDGET (pbar);
675
676   if (amount <= 0)
677     return;
678
679   switch (orientation)
680     {
681     case GTK_PROGRESS_LEFT_TO_RIGHT:
682     case GTK_PROGRESS_RIGHT_TO_LEFT:
683       area.width = amount;
684       area.height = widget->allocation.height - widget->style->ythickness * 2;
685       area.y = widget->style->ythickness;
686       
687       area.x = widget->style->xthickness;
688       if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
689         area.x = widget->allocation.width - amount - area.x;
690       break;
691       
692     case GTK_PROGRESS_TOP_TO_BOTTOM:
693     case GTK_PROGRESS_BOTTOM_TO_TOP:
694       area.width = widget->allocation.width - widget->style->xthickness * 2;
695       area.height = amount;
696       area.x = widget->style->xthickness;
697       
698       area.y = widget->style->ythickness;
699       if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
700         area.y = widget->allocation.height - amount - area.y;
701       break;
702       
703     default:
704       return;
705       break;
706     }
707   
708   gtk_paint_box (widget->style,
709                  GTK_PROGRESS (pbar)->offscreen_pixmap,
710                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
711                  &area, widget, "bar",
712                  area.x, area.y, area.width, area.height);
713 }
714
715 static void
716 gtk_progress_bar_paint_discrete (GtkProgressBar            *pbar,
717                                  GtkProgressBarOrientation  orientation)
718 {
719   GtkWidget *widget = GTK_WIDGET (pbar);
720   gint i;
721
722   for (i = 0; i <= pbar->in_block; i++)
723     {
724       GdkRectangle area;
725       gint space;
726
727       switch (orientation)
728         {
729         case GTK_PROGRESS_LEFT_TO_RIGHT:
730         case GTK_PROGRESS_RIGHT_TO_LEFT:
731           space = widget->allocation.width - 2 * widget->style->xthickness;
732           
733           area.x = widget->style->xthickness + (i * space) / pbar->blocks;
734           area.y = widget->style->ythickness;
735           area.width = widget->style->xthickness + ((i + 1) * space) / pbar->blocks - area.x;
736           area.height = widget->allocation.height - 2 * widget->style->ythickness;
737
738           if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
739             area.x = widget->allocation.width - area.width - area.x;
740           break;
741           
742         case GTK_PROGRESS_TOP_TO_BOTTOM:
743         case GTK_PROGRESS_BOTTOM_TO_TOP:
744           space = widget->allocation.height - 2 * widget->style->ythickness;
745           
746           area.x = widget->style->xthickness;
747           area.y = widget->style->ythickness + (i * space) / pbar->blocks;
748           area.width = widget->allocation.width - 2 * widget->style->xthickness;
749           area.height = widget->style->ythickness + ((i + 1) * space) / pbar->blocks - area.y;
750           
751           if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
752             area.y = widget->allocation.height - area.height - area.y;
753           break;
754
755         default:
756           return;
757           break;
758         }
759       
760       gtk_paint_box (widget->style,
761                      GTK_PROGRESS (pbar)->offscreen_pixmap,
762                      GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
763                      &area, widget, "bar",
764                      area.x, area.y, area.width, area.height);
765     }
766 }
767
768 static void
769 gtk_progress_bar_paint_text (GtkProgressBar            *pbar,
770                              gint                       offset,
771                              gint                       amount,
772                              GtkProgressBarOrientation  orientation)
773 {
774   GtkProgress *progress = GTK_PROGRESS (pbar);
775   GtkWidget *widget = GTK_WIDGET (pbar);
776   gint x;
777   gint y;
778   gchar *buf;
779   GdkRectangle rect;
780   PangoLayout *layout;
781   PangoRectangle logical_rect;
782   GdkRectangle prelight_clip, normal_clip;
783   gfloat text_xalign = progress->x_align;
784   gfloat text_yalign = progress->y_align;
785
786   if (gtk_widget_get_direction (widget) != GTK_TEXT_DIR_LTR)
787     text_xalign = 1.0 - text_xalign;
788
789   buf = gtk_progress_get_current_text (progress);
790   
791   layout = gtk_widget_create_pango_layout (widget, buf);
792   pango_layout_set_ellipsize (layout, pbar->ellipsize);
793   if (pbar->ellipsize)
794     pango_layout_set_width (layout, widget->allocation.width * PANGO_SCALE);
795
796   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
797   
798   x = widget->style->xthickness + 1 + text_xalign *
799       (widget->allocation.width - 2 * widget->style->xthickness -
800        2 - logical_rect.width);
801
802   y = widget->style->ythickness + 1 + text_yalign *
803       (widget->allocation.height - 2 * widget->style->ythickness -
804        2 - logical_rect.height);
805
806   rect.x = widget->style->xthickness;
807   rect.y = widget->style->ythickness;
808   rect.width = widget->allocation.width - 2 * widget->style->xthickness;
809   rect.height = widget->allocation.height - 2 * widget->style->ythickness;
810
811   prelight_clip = normal_clip = rect;
812
813   switch (orientation)
814     {
815     case GTK_PROGRESS_LEFT_TO_RIGHT:
816       if (offset != -1)
817         prelight_clip.x = offset;
818       prelight_clip.width = amount;
819       break;
820       
821     case GTK_PROGRESS_RIGHT_TO_LEFT:
822       if (offset != -1)
823         prelight_clip.x = offset;
824       else
825         prelight_clip.x = rect.x + rect.width - amount;
826       prelight_clip.width = amount;
827       break;
828        
829     case GTK_PROGRESS_TOP_TO_BOTTOM:
830       if (offset != -1)
831         prelight_clip.y = offset;
832       prelight_clip.height = amount;
833       break;
834       
835     case GTK_PROGRESS_BOTTOM_TO_TOP:
836       if (offset != -1)
837         prelight_clip.y = offset;
838       else
839         prelight_clip.y = rect.y + rect.height - amount;
840       prelight_clip.height = amount;
841       break;
842     }
843
844   gtk_paint_layout (widget->style,
845                     progress->offscreen_pixmap,
846                     GTK_STATE_NORMAL,
847                     FALSE,
848                     &normal_clip,
849                     widget,
850                     "progressbar",
851                     x, y,
852                     layout);
853
854   gtk_paint_layout (widget->style,
855                     progress->offscreen_pixmap,
856                     GTK_STATE_PRELIGHT,
857                     FALSE,
858                     &prelight_clip,
859                     widget,
860                     "progressbar",
861                     x, y,
862                     layout);
863
864   g_object_unref (layout);
865   g_free (buf);
866 }
867
868 static void
869 gtk_progress_bar_paint (GtkProgress *progress)
870 {
871   GtkProgressBar *pbar;
872   GtkWidget *widget;
873
874   GtkProgressBarOrientation orientation;
875
876   g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
877
878   pbar = GTK_PROGRESS_BAR (progress);
879   widget = GTK_WIDGET (progress);
880
881   orientation = pbar->orientation;
882   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
883     {
884       if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
885         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
886       else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
887         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
888     }
889  
890   if (progress->offscreen_pixmap)
891     {
892       gtk_paint_box (widget->style,
893                      progress->offscreen_pixmap,
894                      GTK_STATE_NORMAL, GTK_SHADOW_IN, 
895                      NULL, widget, "trough",
896                      0, 0,
897                      widget->allocation.width,
898                      widget->allocation.height);
899       
900       if (progress->activity_mode)
901         {
902           gtk_progress_bar_paint_activity (pbar, orientation);
903
904           if (GTK_PROGRESS (pbar)->show_text)
905             {
906               gint offset;
907               gint amount;
908
909               gtk_progress_bar_get_activity (pbar, orientation, &offset, &amount);
910               gtk_progress_bar_paint_text (pbar, offset, amount, orientation);
911             }
912         }
913       else
914         {
915           gint amount;
916           gint space;
917           
918           if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
919               orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
920             space = widget->allocation.width - 2 * widget->style->xthickness;
921           else
922             space = widget->allocation.height - 2 * widget->style->ythickness;
923           
924           amount = space *
925             gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
926           
927           if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
928             {
929               gtk_progress_bar_paint_continuous (pbar, amount, orientation);
930
931               if (GTK_PROGRESS (pbar)->show_text)
932                 gtk_progress_bar_paint_text (pbar, -1, amount, orientation);
933             }
934           else
935             gtk_progress_bar_paint_discrete (pbar, orientation);
936         }
937
938       pbar->dirty = FALSE;
939     }
940 }
941
942 static void
943 gtk_progress_bar_set_bar_style_internal (GtkProgressBar     *pbar,
944                                          GtkProgressBarStyle bar_style)
945 {
946   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
947
948   if (pbar->bar_style != bar_style)
949     {
950       pbar->bar_style = bar_style;
951
952       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
953         gtk_widget_queue_resize (GTK_WIDGET (pbar));
954
955       g_object_notify (G_OBJECT (pbar), "bar-style");
956     }
957 }
958
959 static void
960 gtk_progress_bar_set_discrete_blocks_internal (GtkProgressBar *pbar,
961                                                guint           blocks)
962 {
963   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
964   g_return_if_fail (blocks > 1);
965
966   if (pbar->blocks != blocks)
967     {
968       pbar->blocks = blocks;
969
970       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
971         gtk_widget_queue_resize (GTK_WIDGET (pbar));
972
973       g_object_notify (G_OBJECT (pbar), "discrete-blocks");
974     }
975 }
976
977 static void
978 gtk_progress_bar_set_activity_step_internal (GtkProgressBar *pbar,
979                                              guint           step)
980 {
981   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
982
983   if (pbar->activity_step != step)
984     {
985       pbar->activity_step = step;
986       g_object_notify (G_OBJECT (pbar), "activity-step");
987     }
988 }
989
990 static void
991 gtk_progress_bar_set_activity_blocks_internal (GtkProgressBar *pbar,
992                                                guint           blocks)
993 {
994   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
995   g_return_if_fail (blocks > 1);
996
997   if (pbar->activity_blocks != blocks)
998     {
999       pbar->activity_blocks = blocks;
1000       g_object_notify (G_OBJECT (pbar), "activity-blocks");
1001     }
1002 }
1003
1004 /*******************************************************************/
1005
1006 /**
1007  * gtk_progress_bar_set_fraction:
1008  * @pbar: a #GtkProgressBar
1009  * @fraction: fraction of the task that's been completed
1010  * 
1011  * Causes the progress bar to "fill in" the given fraction
1012  * of the bar. The fraction should be between 0.0 and 1.0,
1013  * inclusive.
1014  * 
1015  **/
1016 void
1017 gtk_progress_bar_set_fraction (GtkProgressBar *pbar,
1018                                gdouble         fraction)
1019 {
1020   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1021
1022   /* If we know the percentage, we don't want activity mode. */
1023   gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), FALSE);
1024   
1025   /* We use the deprecated GtkProgress interface internally.
1026    * Once everything's been deprecated for a good long time,
1027    * we can clean up all this code.
1028    */
1029   gtk_progress_set_percentage (GTK_PROGRESS (pbar), fraction);
1030
1031   g_object_notify (G_OBJECT (pbar), "fraction");
1032 }
1033
1034 /**
1035  * gtk_progress_bar_pulse:
1036  * @pbar: a #GtkProgressBar
1037  * 
1038  * Indicates that some progress is made, but you don't know how much.
1039  * Causes the progress bar to enter "activity mode," where a block
1040  * bounces back and forth. Each call to gtk_progress_bar_pulse()
1041  * causes the block to move by a little bit (the amount of movement
1042  * per pulse is determined by gtk_progress_bar_set_pulse_step()).
1043  **/
1044 void
1045 gtk_progress_bar_pulse (GtkProgressBar *pbar)
1046 {  
1047   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1048
1049   /* If we don't know the percentage, we must want activity mode. */
1050   gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), TRUE);
1051
1052   /* Sigh. */
1053   gtk_progress_bar_real_update (GTK_PROGRESS (pbar));
1054 }
1055
1056 /**
1057  * gtk_progress_bar_set_text:
1058  * @pbar: a #GtkProgressBar
1059  * @text: a UTF-8 string, or %NULL 
1060  * 
1061  * Causes the given @text to appear superimposed on the progress bar.
1062  **/
1063 void
1064 gtk_progress_bar_set_text (GtkProgressBar *pbar,
1065                            const gchar    *text)
1066 {
1067   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1068   
1069   gtk_progress_set_show_text (GTK_PROGRESS (pbar), text && *text);
1070   gtk_progress_set_format_string (GTK_PROGRESS (pbar), text);
1071   
1072   /* We don't support formats in this interface, but turn
1073    * them back on for NULL, which should put us back to
1074    * the initial state.
1075    */
1076   GTK_PROGRESS (pbar)->use_text_format = (text == NULL);
1077   
1078   g_object_notify (G_OBJECT (pbar), "text");
1079 }
1080
1081 /**
1082  * gtk_progress_bar_set_pulse_step:
1083  * @pbar: a #GtkProgressBar
1084  * @fraction: fraction between 0.0 and 1.0
1085  * 
1086  * Sets the fraction of total progress bar length to move the
1087  * bouncing block for each call to gtk_progress_bar_pulse().
1088  **/
1089 void
1090 gtk_progress_bar_set_pulse_step   (GtkProgressBar *pbar,
1091                                    gdouble         fraction)
1092 {
1093   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1094   
1095   pbar->pulse_fraction = fraction;
1096
1097   g_object_notify (G_OBJECT (pbar), "pulse-step");
1098 }
1099
1100 void
1101 gtk_progress_bar_update (GtkProgressBar *pbar,
1102                          gdouble         percentage)
1103 {
1104   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1105
1106   /* Use of gtk_progress_bar_update() is deprecated ! 
1107    * Use gtk_progress_bar_set_percentage ()
1108    */   
1109
1110   gtk_progress_set_percentage (GTK_PROGRESS (pbar), percentage);
1111 }
1112
1113 /**
1114  * gtk_progress_bar_set_orientation:
1115  * @pbar: a #GtkProgressBar
1116  * @orientation: orientation of the progress bar
1117  * 
1118  * Causes the progress bar to switch to a different orientation
1119  * (left-to-right, right-to-left, top-to-bottom, or bottom-to-top). 
1120  **/
1121 void
1122 gtk_progress_bar_set_orientation (GtkProgressBar           *pbar,
1123                                   GtkProgressBarOrientation orientation)
1124 {
1125   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1126
1127   if (pbar->orientation != orientation)
1128     {
1129       pbar->orientation = orientation;
1130
1131       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
1132         gtk_widget_queue_resize (GTK_WIDGET (pbar));
1133
1134       g_object_notify (G_OBJECT (pbar), "orientation");
1135     }
1136 }
1137
1138 /**
1139  * gtk_progress_bar_get_text:
1140  * @pbar: a #GtkProgressBar
1141  * 
1142  * Retrieves the text displayed superimposed on the progress bar,
1143  * if any, otherwise %NULL. The return value is a reference
1144  * to the text, not a copy of it, so will become invalid
1145  * if you change the text in the progress bar.
1146  * 
1147  * Return value: text, or %NULL; this string is owned by the widget
1148  * and should not be modified or freed.
1149  **/
1150 G_CONST_RETURN gchar*
1151 gtk_progress_bar_get_text (GtkProgressBar *pbar)
1152 {
1153   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), NULL);
1154
1155   if (GTK_PROGRESS (pbar)->use_text_format)
1156     return NULL;
1157   else
1158     return GTK_PROGRESS (pbar)->format;
1159 }
1160
1161 /**
1162  * gtk_progress_bar_get_fraction:
1163  * @pbar: a #GtkProgressBar
1164  * 
1165  * Returns the current fraction of the task that's been completed.
1166  * 
1167  * Return value: a fraction from 0.0 to 1.0
1168  **/
1169 gdouble
1170 gtk_progress_bar_get_fraction (GtkProgressBar *pbar)
1171 {
1172   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1173
1174   return gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
1175 }
1176
1177 /**
1178  * gtk_progress_bar_get_pulse_step:
1179  * @pbar: a #GtkProgressBar
1180  * 
1181  * Retrieves the pulse step set with gtk_progress_bar_set_pulse_step()
1182  * 
1183  * Return value: a fraction from 0.0 to 1.0
1184  **/
1185 gdouble
1186 gtk_progress_bar_get_pulse_step (GtkProgressBar *pbar)
1187 {
1188   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1189
1190   return pbar->pulse_fraction;
1191 }
1192
1193 /**
1194  * gtk_progress_bar_get_orientation:
1195  * @pbar: a #GtkProgressBar
1196  * 
1197  * Retrieves the current progress bar orientation.
1198  * 
1199  * Return value: orientation of the progress bar
1200  **/
1201 GtkProgressBarOrientation
1202 gtk_progress_bar_get_orientation (GtkProgressBar *pbar)
1203 {
1204   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1205
1206   return pbar->orientation;
1207 }
1208
1209 void
1210 gtk_progress_bar_set_bar_style (GtkProgressBar     *pbar,
1211                                 GtkProgressBarStyle bar_style)
1212 {
1213   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1214
1215   gtk_progress_bar_set_bar_style_internal (pbar, bar_style);
1216 }
1217
1218 void
1219 gtk_progress_bar_set_discrete_blocks (GtkProgressBar *pbar,
1220                                       guint           blocks)
1221 {
1222   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1223   g_return_if_fail (blocks > 1);
1224
1225   gtk_progress_bar_set_discrete_blocks_internal (pbar, blocks);
1226 }
1227
1228 void
1229 gtk_progress_bar_set_activity_step (GtkProgressBar *pbar,
1230                                     guint           step)
1231 {
1232   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1233
1234   gtk_progress_bar_set_activity_step_internal (pbar, step);
1235 }
1236
1237 void
1238 gtk_progress_bar_set_activity_blocks (GtkProgressBar *pbar,
1239                                       guint           blocks)
1240 {
1241   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1242   g_return_if_fail (blocks > 1);
1243
1244   gtk_progress_bar_set_activity_blocks_internal (pbar, blocks);
1245 }
1246
1247 /**
1248  * gtk_progress_bar_set_ellipsize:
1249  * @pbar: a #GtkProgressBar
1250  * @mode: a #PangoEllipsizeMode
1251  *
1252  * Sets the mode used to ellipsize (add an ellipsis: "...") the text 
1253  * if there is not enough space to render the entire string.
1254  *
1255  * Since: 2.6
1256  **/
1257 void
1258 gtk_progress_bar_set_ellipsize (GtkProgressBar     *pbar,
1259                                 PangoEllipsizeMode  mode)
1260 {
1261   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1262   g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && 
1263                     mode <= PANGO_ELLIPSIZE_END);
1264   
1265   if ((PangoEllipsizeMode)pbar->ellipsize != mode)
1266     {
1267       pbar->ellipsize = mode;
1268
1269       g_object_notify (G_OBJECT (pbar), "ellipsize");
1270       gtk_widget_queue_resize (GTK_WIDGET (pbar));
1271     }
1272 }
1273
1274 /**
1275  * gtk_progress_bar_get_ellipsize:
1276  * @pbar: a #GtkProgressBar
1277  *
1278  * Returns the ellipsizing position of the progressbar. 
1279  * See gtk_progress_bar_set_ellipsize().
1280  *
1281  * Return value: #PangoEllipsizeMode
1282  *
1283  * Since: 2.6
1284  **/
1285 PangoEllipsizeMode 
1286 gtk_progress_bar_get_ellipsize (GtkProgressBar *pbar)
1287 {
1288   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), PANGO_ELLIPSIZE_NONE);
1289
1290   return pbar->ellipsize;
1291 }
1292
1293 #define __GTK_PROGRESS_BAR_C__
1294 #include "gtkaliasdef.c"