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