]> Pileus Git - ~andy/gtk/blob - gtk/gtkprogressbar.c
Use canonical names for g_object_notify() as well.
[~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, "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   gint size;
578   GtkProgressBarOrientation orientation;
579
580   pbar = GTK_PROGRESS_BAR (progress);
581   widget = GTK_WIDGET (progress);
582
583   orientation = pbar->orientation;
584   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
585     {
586       if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
587         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
588       else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
589         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
590     }
591   
592   /* calculate start pos */
593
594   if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
595       orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
596     {
597       size = MAX (2, widget->allocation.width / pbar->activity_blocks);
598
599       if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
600         {
601           pbar->activity_pos = widget->style->xthickness;
602           pbar->activity_dir = 0;
603         }
604       else
605         {
606           pbar->activity_pos = widget->allocation.width - 
607             widget->style->xthickness - (widget->allocation.height - 
608                 widget->style->ythickness * 2);
609           pbar->activity_dir = 1;
610         }
611     }
612   else
613     {
614       size = MAX (2, widget->allocation.height / pbar->activity_blocks);
615
616       if (orientation == GTK_PROGRESS_TOP_TO_BOTTOM)
617         {
618           pbar->activity_pos = widget->style->ythickness;
619           pbar->activity_dir = 0;
620         }
621       else
622         {
623           pbar->activity_pos = widget->allocation.height -
624             widget->style->ythickness - (widget->allocation.width - 
625                 widget->style->xthickness * 2);
626           pbar->activity_dir = 1;
627         }
628     }
629 }
630
631 static void
632 gtk_progress_bar_paint_activity (GtkProgressBar            *pbar,
633                                  GtkProgressBarOrientation  orientation)
634 {
635   GtkWidget *widget = GTK_WIDGET (pbar);
636   GtkProgress *progress = GTK_PROGRESS (pbar);
637   gint x, y, w, h;
638
639   switch (orientation)
640     {
641     case GTK_PROGRESS_LEFT_TO_RIGHT:
642     case GTK_PROGRESS_RIGHT_TO_LEFT:
643       x = pbar->activity_pos;
644       y = widget->style->ythickness;
645       w = MAX (2, widget->allocation.width / pbar->activity_blocks);
646       h = 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       x = widget->style->xthickness;
652       y = pbar->activity_pos;
653       w = widget->allocation.width - 2 * widget->style->xthickness;
654       h = MAX (2, widget->allocation.height / pbar->activity_blocks);
655       break;
656
657     default:
658       return;
659       break;
660     }
661
662   gtk_paint_box (widget->style,
663                  progress->offscreen_pixmap,
664                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
665                  NULL, widget, "bar",
666                  x, y, w, h);
667 }
668
669 static void
670 gtk_progress_bar_paint_continuous (GtkProgressBar            *pbar,
671                                    gint                       amount,
672                                    GtkProgressBarOrientation  orientation)
673 {
674   GtkWidget *widget = GTK_WIDGET (pbar);
675   gint x, y, w, h;
676
677   if (amount <= 0)
678     return;
679
680   switch (orientation)
681     {
682     case GTK_PROGRESS_LEFT_TO_RIGHT:
683     case GTK_PROGRESS_RIGHT_TO_LEFT:
684       w = amount;
685       h = widget->allocation.height - widget->style->ythickness * 2;
686       y = widget->style->ythickness;
687       
688       x = widget->style->xthickness;
689       if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
690         x = widget->allocation.width - amount - x;
691       break;
692       
693     case GTK_PROGRESS_TOP_TO_BOTTOM:
694     case GTK_PROGRESS_BOTTOM_TO_TOP:
695       w = widget->allocation.width - widget->style->xthickness * 2;
696       h = amount;
697       x = widget->style->xthickness;
698       
699       y = widget->style->ythickness;
700       if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
701         y = widget->allocation.height - amount - y;
702       break;
703       
704     default:
705       return;
706       break;
707     }
708   
709   gtk_paint_box (widget->style,
710                  GTK_PROGRESS (pbar)->offscreen_pixmap,
711                  GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
712                  NULL, widget, "bar",
713                  x, y, w, h);
714 }
715
716 static void
717 gtk_progress_bar_paint_discrete (GtkProgressBar            *pbar,
718                                  GtkProgressBarOrientation  orientation)
719 {
720   GtkWidget *widget = GTK_WIDGET (pbar);
721   gint i;
722
723   for (i = 0; i <= pbar->in_block; i++)
724     {
725       gint x, y, w, h, 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           x = widget->style->xthickness + (i * space) / pbar->blocks;
734           y = widget->style->ythickness;
735           w = widget->style->xthickness + ((i + 1) * space) / pbar->blocks - x;
736           h = widget->allocation.height - 2 * widget->style->ythickness;
737
738           if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
739             x = widget->allocation.width - w - 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           x = widget->style->xthickness;
747           y = widget->style->ythickness + (i * space) / pbar->blocks;
748           w = widget->allocation.width - 2 * widget->style->xthickness;
749           h = widget->style->ythickness + ((i + 1) * space) / pbar->blocks - y;
750           
751           if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
752             y = widget->allocation.height - h - 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                      NULL, widget, "bar",
764                      x, y, w, h);
765     }
766 }
767
768 static void
769 gtk_progress_bar_paint_text (GtkProgressBar            *pbar,
770                              gint                       amount,
771                              GtkProgressBarOrientation  orientation)
772 {
773   GtkProgress *progress = GTK_PROGRESS (pbar);
774   GtkWidget *widget = GTK_WIDGET (pbar);
775   
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   
784   buf = gtk_progress_get_current_text (progress);
785   
786   layout = gtk_widget_create_pango_layout (widget, buf);
787   pango_layout_set_ellipsize (layout, pbar->ellipsize);
788   if (pbar->ellipsize)
789     pango_layout_set_width (layout, widget->allocation.width * PANGO_SCALE);
790
791   pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
792   
793   x = widget->style->xthickness + 1 +
794     (widget->allocation.width - 2 * widget->style->xthickness -
795      2 - logical_rect.width)
796     * progress->x_align; 
797
798   y = widget->style->ythickness + 1 +
799     (widget->allocation.height - 2 * widget->style->ythickness -
800      2 - logical_rect.height)
801     * progress->y_align;
802
803   rect.x = widget->style->xthickness;
804   rect.y = widget->style->ythickness;
805   rect.width = widget->allocation.width - 2 * widget->style->xthickness;
806   rect.height = widget->allocation.height - 2 * widget->style->ythickness;
807
808   prelight_clip = normal_clip = rect;
809
810   switch (orientation)
811     {
812     case GTK_PROGRESS_LEFT_TO_RIGHT:
813       prelight_clip.width = amount;
814       normal_clip.x += amount;
815       normal_clip.width -= amount;
816       break;
817       
818     case GTK_PROGRESS_RIGHT_TO_LEFT:
819       normal_clip.width -= amount;
820       prelight_clip.x += normal_clip.width;
821       prelight_clip.width -= normal_clip.width;
822       break;
823        
824     case GTK_PROGRESS_TOP_TO_BOTTOM:
825       prelight_clip.height = amount;
826       normal_clip.y += amount;
827       normal_clip.height -= amount;
828       break;
829       
830     case GTK_PROGRESS_BOTTOM_TO_TOP:
831       normal_clip.height -= amount;
832       prelight_clip.y += normal_clip.height;
833       prelight_clip.height -= normal_clip.height;
834       break;
835     }
836   
837   gtk_paint_layout (widget->style,
838                     progress->offscreen_pixmap,
839                     GTK_STATE_PRELIGHT,
840                     FALSE,
841                     &prelight_clip,
842                     widget,
843                     "progressbar",
844                     x, y,
845                     layout);
846   
847   gtk_paint_layout (widget->style,
848                     progress->offscreen_pixmap,
849                     GTK_STATE_NORMAL,
850                     FALSE,
851                     &normal_clip,
852                     widget,
853                     "progressbar",
854                     x, y,
855                     layout);
856
857   g_object_unref (layout);
858   g_free (buf);
859 }
860
861 static void
862 gtk_progress_bar_paint (GtkProgress *progress)
863 {
864   GtkProgressBar *pbar;
865   GtkWidget *widget;
866
867   GtkProgressBarOrientation orientation;
868
869   g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
870
871   pbar = GTK_PROGRESS_BAR (progress);
872   widget = GTK_WIDGET (progress);
873
874   orientation = pbar->orientation;
875   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
876     {
877       if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
878         orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
879       else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
880         orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
881     }
882  
883   if (progress->offscreen_pixmap)
884     {
885       gtk_paint_box (widget->style,
886                      progress->offscreen_pixmap,
887                      GTK_STATE_NORMAL, GTK_SHADOW_IN, 
888                      NULL, widget, "trough",
889                      0, 0,
890                      widget->allocation.width,
891                      widget->allocation.height);
892       
893       if (progress->activity_mode)
894         {
895           gtk_progress_bar_paint_activity (pbar, orientation);
896         }
897       else
898         {
899           gint amount;
900           gint space;
901           
902           if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
903               orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
904             space = widget->allocation.width - 2 * widget->style->xthickness;
905           else
906             space = widget->allocation.height - 2 * widget->style->ythickness;
907           
908           amount = space *
909             gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
910           
911           if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
912             {
913               gtk_progress_bar_paint_continuous (pbar, amount, orientation);
914
915               if (GTK_PROGRESS (pbar)->show_text)
916                 gtk_progress_bar_paint_text (pbar, amount, orientation);
917             }
918           else
919             gtk_progress_bar_paint_discrete (pbar, orientation);
920         }
921     }
922 }
923
924 static void
925 gtk_progress_bar_set_bar_style_internal (GtkProgressBar     *pbar,
926                                          GtkProgressBarStyle bar_style)
927 {
928   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
929
930   if (pbar->bar_style != bar_style)
931     {
932       pbar->bar_style = bar_style;
933
934       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
935         gtk_widget_queue_resize (GTK_WIDGET (pbar));
936
937       g_object_notify (G_OBJECT (pbar), "bar-style");
938     }
939 }
940
941 static void
942 gtk_progress_bar_set_discrete_blocks_internal (GtkProgressBar *pbar,
943                                                guint           blocks)
944 {
945   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
946   g_return_if_fail (blocks > 1);
947
948   if (pbar->blocks != blocks)
949     {
950       pbar->blocks = blocks;
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), "discrete-blocks");
956     }
957 }
958
959 static void
960 gtk_progress_bar_set_activity_step_internal (GtkProgressBar *pbar,
961                                              guint           step)
962 {
963   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
964
965   if (pbar->activity_step != step)
966     {
967       pbar->activity_step = step;
968       g_object_notify (G_OBJECT (pbar), "activity-step");
969     }
970 }
971
972 static void
973 gtk_progress_bar_set_activity_blocks_internal (GtkProgressBar *pbar,
974                                                guint           blocks)
975 {
976   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
977   g_return_if_fail (blocks > 1);
978
979   if (pbar->activity_blocks != blocks)
980     {
981       pbar->activity_blocks = blocks;
982       g_object_notify (G_OBJECT (pbar), "activity-blocks");
983     }
984 }
985
986 /*******************************************************************/
987
988 /**
989  * gtk_progress_bar_set_fraction:
990  * @pbar: a #GtkProgressBar
991  * @fraction: fraction of the task that's been completed
992  * 
993  * Causes the progress bar to "fill in" the given fraction
994  * of the bar. The fraction should be between 0.0 and 1.0,
995  * inclusive.
996  * 
997  **/
998 void
999 gtk_progress_bar_set_fraction (GtkProgressBar *pbar,
1000                                gdouble         fraction)
1001 {
1002   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1003
1004   /* If we know the percentage, we don't want activity mode. */
1005   gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), FALSE);
1006   
1007   /* We use the deprecated GtkProgress interface internally.
1008    * Once everything's been deprecated for a good long time,
1009    * we can clean up all this code.
1010    */
1011   gtk_progress_set_percentage (GTK_PROGRESS (pbar), fraction);
1012
1013   g_object_notify (G_OBJECT (pbar), "fraction");
1014 }
1015
1016 /**
1017  * gtk_progress_bar_pulse:
1018  * @pbar: a #GtkProgressBar
1019  * 
1020  * Indicates that some progress is made, but you don't know how much.
1021  * Causes the progress bar to enter "activity mode," where a block
1022  * bounces back and forth. Each call to gtk_progress_bar_pulse()
1023  * causes the block to move by a little bit (the amount of movement
1024  * per pulse is determined by gtk_progress_bar_set_pulse_step()).
1025  **/
1026 void
1027 gtk_progress_bar_pulse (GtkProgressBar *pbar)
1028 {  
1029   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1030
1031   /* If we don't know the percentage, we must want activity mode. */
1032   gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), TRUE);
1033
1034   /* Sigh. */
1035   gtk_progress_bar_real_update (GTK_PROGRESS (pbar));
1036 }
1037
1038 /**
1039  * gtk_progress_bar_set_text:
1040  * @pbar: a #GtkProgressBar
1041  * @text: a UTF-8 string
1042  * 
1043  * Causes the given @text to appear superimposed on the progress bar.
1044  **/
1045 void
1046 gtk_progress_bar_set_text (GtkProgressBar *pbar,
1047                            const gchar    *text)
1048 {
1049   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1050   
1051   gtk_progress_set_show_text (GTK_PROGRESS (pbar), text && *text);
1052   gtk_progress_set_format_string (GTK_PROGRESS (pbar), text);
1053   
1054   /* We don't support formats in this interface, but turn
1055    * them back on for NULL, which should put us back to
1056    * the initial state.
1057    */
1058   GTK_PROGRESS (pbar)->use_text_format = (text == NULL);
1059   
1060   g_object_notify (G_OBJECT (pbar), "text");
1061 }
1062
1063 /**
1064  * gtk_progress_bar_set_pulse_step:
1065  * @pbar: a #GtkProgressBar
1066  * @fraction: fraction between 0.0 and 1.0
1067  * 
1068  * Sets the fraction of total progress bar length to move the
1069  * bouncing block for each call to gtk_progress_bar_pulse().
1070  **/
1071 void
1072 gtk_progress_bar_set_pulse_step   (GtkProgressBar *pbar,
1073                                    gdouble         fraction)
1074 {
1075   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1076   
1077   pbar->pulse_fraction = fraction;
1078
1079   g_object_notify (G_OBJECT (pbar), "pulse-step");
1080 }
1081
1082 void
1083 gtk_progress_bar_update (GtkProgressBar *pbar,
1084                          gdouble         percentage)
1085 {
1086   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1087
1088   /* Use of gtk_progress_bar_update() is deprecated ! 
1089    * Use gtk_progress_bar_set_percentage ()
1090    */   
1091
1092   gtk_progress_set_percentage (GTK_PROGRESS (pbar), percentage);
1093 }
1094
1095 /**
1096  * gtk_progress_bar_set_orientation:
1097  * @pbar: a #GtkProgressBar
1098  * @orientation: orientation of the progress bar
1099  * 
1100  * Causes the progress bar to switch to a different orientation
1101  * (left-to-right, right-to-left, top-to-bottom, or bottom-to-top). 
1102  **/
1103 void
1104 gtk_progress_bar_set_orientation (GtkProgressBar           *pbar,
1105                                   GtkProgressBarOrientation orientation)
1106 {
1107   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1108
1109   if (pbar->orientation != orientation)
1110     {
1111       pbar->orientation = orientation;
1112
1113       if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
1114         gtk_widget_queue_resize (GTK_WIDGET (pbar));
1115
1116       g_object_notify (G_OBJECT (pbar), "orientation");
1117     }
1118 }
1119
1120 /**
1121  * gtk_progress_bar_get_text:
1122  * @pbar: a #GtkProgressBar
1123  * 
1124  * Retrieves the text displayed superimposed on the progress bar,
1125  * if any, otherwise %NULL. The return value is a reference
1126  * to the text, not a copy of it, so will become invalid
1127  * if you change the text in the progress bar.
1128  * 
1129  * Return value: text, or %NULL; this string is owned by the widget
1130  * and should not be modified or freed.
1131  **/
1132 G_CONST_RETURN gchar*
1133 gtk_progress_bar_get_text (GtkProgressBar *pbar)
1134 {
1135   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), NULL);
1136
1137   if (GTK_PROGRESS (pbar)->use_text_format)
1138     return NULL;
1139   else
1140     return GTK_PROGRESS (pbar)->format;
1141 }
1142
1143 /**
1144  * gtk_progress_bar_get_fraction:
1145  * @pbar: a #GtkProgressBar
1146  * 
1147  * Returns the current fraction of the task that's been completed.
1148  * 
1149  * Return value: a fraction from 0.0 to 1.0
1150  **/
1151 gdouble
1152 gtk_progress_bar_get_fraction (GtkProgressBar *pbar)
1153 {
1154   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1155
1156   return gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
1157 }
1158
1159 /**
1160  * gtk_progress_bar_get_pulse_step:
1161  * @pbar: a #GtkProgressBar
1162  * 
1163  * Retrieves the pulse step set with gtk_progress_bar_set_pulse_step()
1164  * 
1165  * Return value: a fraction from 0.0 to 1.0
1166  **/
1167 gdouble
1168 gtk_progress_bar_get_pulse_step (GtkProgressBar *pbar)
1169 {
1170   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1171
1172   return pbar->pulse_fraction;
1173 }
1174
1175 /**
1176  * gtk_progress_bar_get_orientation:
1177  * @pbar: a #GtkProgressBar
1178  * 
1179  * Retrieves the current progress bar orientation.
1180  * 
1181  * Return value: orientation of the progress bar
1182  **/
1183 GtkProgressBarOrientation
1184 gtk_progress_bar_get_orientation (GtkProgressBar *pbar)
1185 {
1186   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);
1187
1188   return pbar->orientation;
1189 }
1190
1191 void
1192 gtk_progress_bar_set_bar_style (GtkProgressBar     *pbar,
1193                                 GtkProgressBarStyle bar_style)
1194 {
1195   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1196
1197   gtk_progress_bar_set_bar_style_internal (pbar, bar_style);
1198 }
1199
1200 void
1201 gtk_progress_bar_set_discrete_blocks (GtkProgressBar *pbar,
1202                                       guint           blocks)
1203 {
1204   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1205   g_return_if_fail (blocks > 1);
1206
1207   gtk_progress_bar_set_discrete_blocks_internal (pbar, blocks);
1208 }
1209
1210 void
1211 gtk_progress_bar_set_activity_step (GtkProgressBar *pbar,
1212                                     guint           step)
1213 {
1214   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1215
1216   gtk_progress_bar_set_activity_step_internal (pbar, step);
1217 }
1218
1219 void
1220 gtk_progress_bar_set_activity_blocks (GtkProgressBar *pbar,
1221                                       guint           blocks)
1222 {
1223   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1224   g_return_if_fail (blocks > 1);
1225
1226   gtk_progress_bar_set_activity_blocks_internal (pbar, blocks);
1227 }
1228
1229 /**
1230  * gtk_progress_bar_set_ellipsize:
1231  * @pbar: a #GtkProgressBar
1232  * @mode: a #PangoEllipsizeMode
1233  *
1234  * Sets the mode used to ellipsize (add an ellipsis: "...") the text 
1235  * if there is not enough space to render the entire string.
1236  *
1237  * Since: 2.6
1238  **/
1239 void
1240 gtk_progress_bar_set_ellipsize (GtkProgressBar     *pbar,
1241                                 PangoEllipsizeMode  mode)
1242 {
1243   g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
1244   g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE && 
1245                     mode <= PANGO_ELLIPSIZE_END);
1246   
1247   if ((PangoEllipsizeMode)pbar->ellipsize != mode)
1248     {
1249       pbar->ellipsize = mode;
1250
1251       g_object_notify (G_OBJECT (pbar), "ellipsize");
1252       gtk_widget_queue_resize (GTK_WIDGET (pbar));
1253     }
1254 }
1255
1256 /**
1257  * gtk_progress_bar_get_ellipsize:
1258  * @pbar: a #GtkProgressBar
1259  *
1260  * Returns the ellipsizing position of the progressbar. 
1261  * See gtk_progress_bar_set_ellipsize().
1262  *
1263  * Return value: #PangoEllipsizeMode
1264  *
1265  * Since: 2.6
1266  **/
1267 PangoEllipsizeMode 
1268 gtk_progress_bar_get_ellipsize (GtkProgressBar *pbar)
1269 {
1270   g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), PANGO_ELLIPSIZE_NONE);
1271
1272   return pbar->ellipsize;
1273 }
1274
1275 #define __GTK_PROGRESS_BAR_C__
1276 #include "gtkaliasdef.c"