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