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