gtkprogressbar.c 32.2 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4
/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19

20
/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27 28 29 30 31 32 33 34 35 36
#if HAVE_CONFIG_H
#  include <config.h>
#  if STDC_HEADERS
#    include <string.h>
#    include <stdio.h>
#  endif
#else
#  include <stdio.h>
#endif

Elliot Lee's avatar
Elliot Lee committed
37
#include "gtkprogressbar.h"
Alexander Larsson's avatar
Alexander Larsson committed
38
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
39 40


41 42 43 44 45 46
#define MIN_HORIZONTAL_BAR_WIDTH   150
#define MIN_HORIZONTAL_BAR_HEIGHT  20
#define MIN_VERTICAL_BAR_WIDTH     22
#define MIN_VERTICAL_BAR_HEIGHT    80
#define MAX_TEXT_LENGTH            80
#define TEXT_SPACING               2
Elliot Lee's avatar
Elliot Lee committed
47

48
enum {
Alexander Larsson's avatar
Alexander Larsson committed
49
  PROP_0,
50 51

  /* Supported args */
Alexander Larsson's avatar
Alexander Larsson committed
52 53 54 55
  PROP_FRACTION,
  PROP_PULSE_STEP,
  PROP_ORIENTATION,
  PROP_TEXT,
56 57
  
  /* Deprecated args */
Alexander Larsson's avatar
Alexander Larsson committed
58 59 60 61 62
  PROP_ADJUSTMENT,
  PROP_BAR_STYLE,
  PROP_ACTIVITY_STEP,
  PROP_ACTIVITY_BLOCKS,
  PROP_DISCRETE_BLOCKS
63
};
Elliot Lee's avatar
Elliot Lee committed
64 65 66

static void gtk_progress_bar_class_init    (GtkProgressBarClass *klass);
static void gtk_progress_bar_init          (GtkProgressBar      *pbar);
Alexander Larsson's avatar
Alexander Larsson committed
67 68 69 70 71 72 73 74
static void gtk_progress_bar_set_property  (GObject             *object,
					    guint                prop_id,
					    const GValue        *value,
					    GParamSpec          *pspec);
static void gtk_progress_bar_get_property  (GObject             *object,
					    guint                prop_id,
					    GValue              *value,
					    GParamSpec          *pspec);
75 76 77 78 79
static void gtk_progress_bar_size_request  (GtkWidget           *widget,
					    GtkRequisition      *requisition);
static void gtk_progress_bar_real_update   (GtkProgress         *progress);
static void gtk_progress_bar_paint         (GtkProgress         *progress);
static void gtk_progress_bar_act_mode_enter (GtkProgress        *progress);
Elliot Lee's avatar
Elliot Lee committed
80

81 82 83 84 85 86 87 88 89
static void gtk_progress_bar_set_bar_style_internal       (GtkProgressBar *pbar,
							   GtkProgressBarStyle style);
static void gtk_progress_bar_set_discrete_blocks_internal (GtkProgressBar *pbar,
							   guint           blocks);
static void gtk_progress_bar_set_activity_step_internal   (GtkProgressBar *pbar,
							   guint           step);
static void gtk_progress_bar_set_activity_blocks_internal (GtkProgressBar *pbar,
							   guint           blocks);

Elliot Lee's avatar
Elliot Lee committed
90

Manish Singh's avatar
Manish Singh committed
91
GType
92
gtk_progress_bar_get_type (void)
Elliot Lee's avatar
Elliot Lee committed
93
{
Manish Singh's avatar
Manish Singh committed
94
  static GType progress_bar_type = 0;
Elliot Lee's avatar
Elliot Lee committed
95 96 97

  if (!progress_bar_type)
    {
Manish Singh's avatar
Manish Singh committed
98
      static const GTypeInfo progress_bar_info =
Elliot Lee's avatar
Elliot Lee committed
99 100
      {
	sizeof (GtkProgressBarClass),
Manish Singh's avatar
Manish Singh committed
101 102 103 104 105 106 107 108
	NULL,		/* base_init */
	NULL,		/* base_finalize */
	(GClassInitFunc) gtk_progress_bar_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof (GtkProgressBar),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gtk_progress_bar_init,
Elliot Lee's avatar
Elliot Lee committed
109 110
      };

Manish Singh's avatar
Manish Singh committed
111 112 113
      progress_bar_type =
	g_type_register_static (GTK_TYPE_PROGRESS, "GtkProgressBar",
				&progress_bar_info, 0);
Elliot Lee's avatar
Elliot Lee committed
114 115 116 117 118 119 120 121
    }

  return progress_bar_type;
}

static void
gtk_progress_bar_class_init (GtkProgressBarClass *class)
{
Alexander Larsson's avatar
Alexander Larsson committed
122
  GObjectClass *gobject_class;
Elliot Lee's avatar
Elliot Lee committed
123
  GtkWidgetClass *widget_class;
124
  GtkProgressClass *progress_class;
125
  
Alexander Larsson's avatar
Alexander Larsson committed
126
  gobject_class = G_OBJECT_CLASS (class);
127 128
  widget_class = (GtkWidgetClass *) class;
  progress_class = (GtkProgressClass *) class;
Elliot Lee's avatar
Elliot Lee committed
129

Alexander Larsson's avatar
Alexander Larsson committed
130 131 132
  gobject_class->set_property = gtk_progress_bar_set_property;
  gobject_class->get_property = gtk_progress_bar_get_property;
  
133
  widget_class->size_request = gtk_progress_bar_size_request;
Elliot Lee's avatar
Elliot Lee committed
134

135 136 137
  progress_class->paint = gtk_progress_bar_paint;
  progress_class->update = gtk_progress_bar_real_update;
  progress_class->act_mode_enter = gtk_progress_bar_act_mode_enter;
Alexander Larsson's avatar
Alexander Larsson committed
138 139 140 141 142 143 144 145 146 147 148 149 150

  g_object_class_install_property (gobject_class,
                                   PROP_ADJUSTMENT,
                                   g_param_spec_object ("adjustment",
                                                        _("Adjustment"),
                                                        _("The GtkAdjustment connected to the progress bar (Deprecated)"),
                                                        GTK_TYPE_ADJUSTMENT,
                                                        G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_ORIENTATION,
                                   g_param_spec_enum ("orientation",
						      _("Orientation"),
Matthias Clasen's avatar
Matthias Clasen committed
151
						      _("Orientation and growth direction of the progress bar"),
Alexander Larsson's avatar
Alexander Larsson committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
						      GTK_TYPE_PROGRESS_BAR_ORIENTATION,
						      GTK_PROGRESS_LEFT_TO_RIGHT,
						      G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_BAR_STYLE,
                                   g_param_spec_enum ("bar_style",
						      _("Bar style"),
						      _("Specifies the visual style of the bar in percentage mode (Deprecated)"),
						      GTK_TYPE_PROGRESS_BAR_STYLE,
						      GTK_PROGRESS_CONTINUOUS,
						      G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_ACTIVITY_STEP,
                                   g_param_spec_uint ("activity_step",
						      _("Activity Step"),
						      _("The increment used for each iteration in activity mode (Deprecated)"),
						      -G_MAXUINT,
						      G_MAXUINT,
						      3,
						      G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_ACTIVITY_BLOCKS,
                                   g_param_spec_uint ("activity_blocks",
						      _("Activity Blocks"),
						      _("The number of blocks which can fit in the progress bar area in activity mode (Deprecated)"),
						      2,
						      G_MAXUINT,
						      5,
						      G_PARAM_READWRITE));

  g_object_class_install_property (gobject_class,
                                   PROP_DISCRETE_BLOCKS,
                                   g_param_spec_uint ("discrete_blocks",
						      _("Discrete Blocks"),
Kjartan Maraas's avatar
Kjartan Maraas committed
189
						      _("The number of discrete blocks in a progress bar (when shown in the discrete style)"),
Alexander Larsson's avatar
Alexander Larsson committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
						      2,
						      G_MAXUINT,
						      10,
						      G_PARAM_READWRITE));
  
  g_object_class_install_property (gobject_class,
				   PROP_FRACTION,
				   g_param_spec_double ("fraction",
							_("Fraction"),
							_("The fraction of total work that has been completed"),
							0.0,
							1.0,
							0.0,
							G_PARAM_READWRITE));  
  
  g_object_class_install_property (gobject_class,
				   PROP_PULSE_STEP,
				   g_param_spec_double ("pulse_step",
							_("Pulse Step"),
							_("The fraction of total progress to move the bouncing block when pulsed"),
							0.0,
							1.0,
							0.1,
							G_PARAM_READWRITE));  
  
  g_object_class_install_property (gobject_class,
				   PROP_TEXT,
				   g_param_spec_string ("text",
							_("Text"),
							_("Text to be displayed in the progress bar"),
							"%P %%",
							G_PARAM_READWRITE));

Elliot Lee's avatar
Elliot Lee committed
223 224 225 226 227
}

static void
gtk_progress_bar_init (GtkProgressBar *pbar)
{
228 229 230 231
  pbar->bar_style = GTK_PROGRESS_CONTINUOUS;
  pbar->blocks = 10;
  pbar->in_block = -1;
  pbar->orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
232
  pbar->pulse_fraction = 0.1;
233 234 235
  pbar->activity_pos = 0;
  pbar->activity_dir = 1;
  pbar->activity_step = 3;
236
  pbar->activity_blocks = 5;
Elliot Lee's avatar
Elliot Lee committed
237 238
}

239
static void
Alexander Larsson's avatar
Alexander Larsson committed
240 241 242 243
gtk_progress_bar_set_property (GObject      *object,
			       guint         prop_id,
			       const GValue *value,
			       GParamSpec   *pspec)
244 245 246 247
{
  GtkProgressBar *pbar;

  pbar = GTK_PROGRESS_BAR (object);
Elliot Lee's avatar
Elliot Lee committed
248

Alexander Larsson's avatar
Alexander Larsson committed
249
  switch (prop_id)
250
    {
Alexander Larsson's avatar
Alexander Larsson committed
251 252 253
    case PROP_ADJUSTMENT:
      gtk_progress_set_adjustment (GTK_PROGRESS (pbar),
				   GTK_ADJUSTMENT (g_value_get_object (value)));
254
      break;
Alexander Larsson's avatar
Alexander Larsson committed
255 256
    case PROP_ORIENTATION:
      gtk_progress_bar_set_orientation (pbar, g_value_get_enum (value));
257
      break;
Alexander Larsson's avatar
Alexander Larsson committed
258
    case PROP_BAR_STYLE:
259
      gtk_progress_bar_set_bar_style_internal (pbar, g_value_get_enum (value));
260
      break;
Alexander Larsson's avatar
Alexander Larsson committed
261
    case PROP_ACTIVITY_STEP:
262
      gtk_progress_bar_set_activity_step_internal (pbar, g_value_get_uint (value));
263
      break;
Alexander Larsson's avatar
Alexander Larsson committed
264
    case PROP_ACTIVITY_BLOCKS:
265
      gtk_progress_bar_set_activity_blocks_internal (pbar, g_value_get_uint (value));
266
      break;
Alexander Larsson's avatar
Alexander Larsson committed
267
    case PROP_DISCRETE_BLOCKS:
268
      gtk_progress_bar_set_discrete_blocks_internal (pbar, g_value_get_uint (value));
269
      break;
Alexander Larsson's avatar
Alexander Larsson committed
270 271
    case PROP_FRACTION:
      gtk_progress_bar_set_fraction (pbar, g_value_get_double (value));
272
      break;
Alexander Larsson's avatar
Alexander Larsson committed
273 274
    case PROP_PULSE_STEP:
      gtk_progress_bar_set_pulse_step (pbar, g_value_get_double (value));
275
      break;
Alexander Larsson's avatar
Alexander Larsson committed
276 277
    case PROP_TEXT:
      gtk_progress_bar_set_text (pbar, g_value_get_string (value));
278
      break;
279
    default:
Alexander Larsson's avatar
Alexander Larsson committed
280
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281 282 283 284 285
      break;
    }
}

static void
Alexander Larsson's avatar
Alexander Larsson committed
286 287 288 289
gtk_progress_bar_get_property (GObject      *object,
			       guint         prop_id,
			       GValue       *value,
			       GParamSpec   *pspec)
Elliot Lee's avatar
Elliot Lee committed
290
{
291 292
  GtkProgressBar *pbar;

293 294
  pbar = GTK_PROGRESS_BAR (object);

Alexander Larsson's avatar
Alexander Larsson committed
295
  switch (prop_id)
296
    {
Alexander Larsson's avatar
Alexander Larsson committed
297
    case PROP_ADJUSTMENT:
298
      g_value_set_object (value, GTK_PROGRESS (pbar)->adjustment);
299
      break;
Alexander Larsson's avatar
Alexander Larsson committed
300 301
    case PROP_ORIENTATION:
      g_value_set_enum (value, pbar->orientation);
302
      break;
Alexander Larsson's avatar
Alexander Larsson committed
303 304
    case PROP_BAR_STYLE:
      g_value_set_enum (value, pbar->bar_style);
305
      break;
Alexander Larsson's avatar
Alexander Larsson committed
306 307
    case PROP_ACTIVITY_STEP:
      g_value_set_uint (value, pbar->activity_step);
308
      break;
Alexander Larsson's avatar
Alexander Larsson committed
309 310
    case PROP_ACTIVITY_BLOCKS:
      g_value_set_uint (value, pbar->activity_blocks);
311
      break;
Alexander Larsson's avatar
Alexander Larsson committed
312 313
    case PROP_DISCRETE_BLOCKS:
      g_value_set_uint (value, pbar->blocks);
314
      break;
Alexander Larsson's avatar
Alexander Larsson committed
315 316
    case PROP_FRACTION:
      g_value_set_double (value, gtk_progress_get_current_percentage (GTK_PROGRESS (pbar)));
317
      break;
Alexander Larsson's avatar
Alexander Larsson committed
318 319
    case PROP_PULSE_STEP:
      g_value_set_double (value, pbar->pulse_fraction);
320
      break;
Alexander Larsson's avatar
Alexander Larsson committed
321 322
    case PROP_TEXT:
      g_value_set_string (value, gtk_progress_bar_get_text (pbar));
323
      break;
324
    default:
Alexander Larsson's avatar
Alexander Larsson committed
325
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
326 327 328 329 330 331 332 333
      break;
    }
}

GtkWidget*
gtk_progress_bar_new (void)
{
  GtkWidget *pbar;
334

335
  pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR, NULL);
336

337
  return pbar;
338 339
}

340
GtkWidget*
341 342
gtk_progress_bar_new_with_adjustment (GtkAdjustment *adjustment)
{
343
  GtkWidget *pbar;
344

345
  g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
346

347 348 349
  pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR,
			 "adjustment", adjustment,
			 NULL);
350

351
  return pbar;
Elliot Lee's avatar
Elliot Lee committed
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366
static void
gtk_progress_bar_real_update (GtkProgress *progress)
{
  GtkProgressBar *pbar;
  GtkWidget *widget;

  g_return_if_fail (GTK_IS_PROGRESS (progress));

  pbar = GTK_PROGRESS_BAR (progress);
  widget = GTK_WIDGET (progress);
 
  if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS ||
      GTK_PROGRESS (pbar)->activity_mode)
Elliot Lee's avatar
Elliot Lee committed
367
    {
368 369 370
      if (GTK_PROGRESS (pbar)->activity_mode)
	{
	  guint size;
371
          
372 373 374 375 376
	  /* advance the block */

	  if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
	      pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	    {
377 378 379 380
              /* Update our activity step. */
              
              pbar->activity_step = widget->allocation.width * pbar->pulse_fraction;
              
381
	      size = MAX (2, widget->allocation.width / pbar->activity_blocks);
382 383 384 385 386 387

	      if (pbar->activity_dir == 0)
		{
		  pbar->activity_pos += pbar->activity_step;
		  if (pbar->activity_pos + size >=
		      widget->allocation.width -
388
		      widget->style->xthickness)
389 390
		    {
		      pbar->activity_pos = widget->allocation.width -
391
			widget->style->xthickness - size;
392 393 394 395 396 397
		      pbar->activity_dir = 1;
		    }
		}
	      else
		{
		  pbar->activity_pos -= pbar->activity_step;
398
		  if (pbar->activity_pos <= widget->style->xthickness)
399
		    {
400
		      pbar->activity_pos = widget->style->xthickness;
401 402 403 404 405 406
		      pbar->activity_dir = 0;
		    }
		}
	    }
	  else
	    {
407 408 409 410
              /* Update our activity step. */
              
              pbar->activity_step = widget->allocation.height * pbar->pulse_fraction;
              
411
	      size = MAX (2, widget->allocation.height / pbar->activity_blocks);
412 413 414 415 416 417

	      if (pbar->activity_dir == 0)
		{
		  pbar->activity_pos += pbar->activity_step;
		  if (pbar->activity_pos + size >=
		      widget->allocation.height -
418
		      widget->style->ythickness)
419 420
		    {
		      pbar->activity_pos = widget->allocation.height -
421
			widget->style->ythickness - size;
422 423 424 425 426 427
		      pbar->activity_dir = 1;
		    }
		}
	      else
		{
		  pbar->activity_pos -= pbar->activity_step;
428
		  if (pbar->activity_pos <= widget->style->ythickness)
429
		    {
430
		      pbar->activity_pos = widget->style->ythickness;
431 432 433 434 435 436 437 438 439 440 441 442 443
		      pbar->activity_dir = 0;
		    }
		}
	    }
	}
      gtk_progress_bar_paint (progress);
      gtk_widget_queue_draw (GTK_WIDGET (progress));
    }
  else
    {
      gint in_block;
      
      in_block = -1 + (gint)(gtk_progress_get_current_percentage (progress) *
444
			     (gdouble)pbar->blocks);
445 446 447 448 449 450 451
      
      if (pbar->in_block != in_block)
	{
	  pbar->in_block = in_block;
	  gtk_progress_bar_paint (progress);
	  gtk_widget_queue_draw (GTK_WIDGET (progress));
	}
Elliot Lee's avatar
Elliot Lee committed
452 453 454 455
    }
}

static void
456 457
gtk_progress_bar_size_request (GtkWidget      *widget,
			       GtkRequisition *requisition)
Elliot Lee's avatar
Elliot Lee committed
458
{
459
  GtkProgress *progress;
Elliot Lee's avatar
Elliot Lee committed
460
  GtkProgressBar *pbar;
461
  gchar *buf;
462 463
  PangoRectangle logical_rect;
  PangoLayout *layout;
Elliot Lee's avatar
Elliot Lee committed
464 465

  g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
466
  g_return_if_fail (requisition != NULL);
Elliot Lee's avatar
Elliot Lee committed
467

468
  progress = GTK_PROGRESS (widget);
Elliot Lee's avatar
Elliot Lee committed
469 470
  pbar = GTK_PROGRESS_BAR (widget);

471 472
  if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
    {
473 474 475
      if (!progress->adjustment)
	gtk_progress_set_adjustment (progress, NULL);

476 477
      buf = gtk_progress_get_text_from_value (progress, progress->adjustment->upper);

478
      layout = gtk_widget_create_pango_layout (widget, buf);
479
      pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
480
	  
Manish Singh's avatar
Manish Singh committed
481
      g_object_unref (layout);
482 483 484
      g_free (buf);
    }
  
485 486 487 488 489 490
  if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
      pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
    {
      if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
	{
	  requisition->width = MAX (MIN_HORIZONTAL_BAR_WIDTH,
491
				    2 * widget->style->xthickness + 3 +
492
				    logical_rect.width + 2 * TEXT_SPACING);
493 494

	  requisition->height = MAX (MIN_HORIZONTAL_BAR_HEIGHT,
495
				     2 * widget->style->ythickness + 3 +
496
				     logical_rect.height + 2 * TEXT_SPACING);
497 498 499 500 501 502 503 504 505 506 507 508
	}
      else
	{
	  requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
	  requisition->height = MIN_HORIZONTAL_BAR_HEIGHT;
	}
    }
  else
    {
      if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
	{	  
	  requisition->width = MAX (MIN_VERTICAL_BAR_WIDTH,
509
				    2 * widget->style->xthickness + 3 +
510
				    logical_rect.width + 2 * TEXT_SPACING);
511 512

	  requisition->height = MAX (MIN_VERTICAL_BAR_HEIGHT,
513
				     2 * widget->style->ythickness + 3 +
514
				     logical_rect.height + 2 * TEXT_SPACING);
515 516 517 518 519 520 521 522
	}
      else
	{
	  requisition->width = MIN_VERTICAL_BAR_WIDTH;
	  requisition->height = MIN_VERTICAL_BAR_HEIGHT;
	}
    }
}
Elliot Lee's avatar
Elliot Lee committed
523

524 525 526 527 528
static void
gtk_progress_bar_act_mode_enter (GtkProgress *progress)
{
  GtkProgressBar *pbar;
  GtkWidget *widget;
529
  gint size;
530
  GtkProgressBarOrientation orientation;
Elliot Lee's avatar
Elliot Lee committed
531

532 533
  pbar = GTK_PROGRESS_BAR (progress);
  widget = GTK_WIDGET (progress);
Elliot Lee's avatar
Elliot Lee committed
534

535 536 537 538 539 540 541 542 543
  orientation = pbar->orientation;
  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
    {
      if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
	orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
      else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
    }
  
544
  /* calculate start pos */
Elliot Lee's avatar
Elliot Lee committed
545

546 547
  if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
      orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
548
    {
549 550
      size = MAX (2, widget->allocation.width / pbar->activity_blocks);

551
      if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
552
	{
553
	  pbar->activity_pos = widget->style->xthickness;
554 555 556 557 558
	  pbar->activity_dir = 0;
	}
      else
	{
	  pbar->activity_pos = widget->allocation.width - 
559 560
	    widget->style->xthickness - (widget->allocation.height - 
		widget->style->ythickness * 2);
561 562 563 564 565
	  pbar->activity_dir = 1;
	}
    }
  else
    {
566 567
      size = MAX (2, widget->allocation.height / pbar->activity_blocks);

568
      if (orientation == GTK_PROGRESS_TOP_TO_BOTTOM)
569
	{
570
	  pbar->activity_pos = widget->style->ythickness;
571 572 573 574 575
	  pbar->activity_dir = 0;
	}
      else
	{
	  pbar->activity_pos = widget->allocation.height -
576 577
	    widget->style->ythickness - (widget->allocation.width - 
		widget->style->xthickness * 2);
578 579 580
	  pbar->activity_dir = 1;
	}
    }
Elliot Lee's avatar
Elliot Lee committed
581 582 583
}

static void
584 585
gtk_progress_bar_paint_activity (GtkProgressBar            *pbar,
				 GtkProgressBarOrientation  orientation)
Elliot Lee's avatar
Elliot Lee committed
586
{
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621
  GtkWidget *widget = GTK_WIDGET (pbar);
  GtkProgress *progress = GTK_PROGRESS (pbar);
  gint x, y, w, h;

  switch (orientation)
    {
    case GTK_PROGRESS_LEFT_TO_RIGHT:
    case GTK_PROGRESS_RIGHT_TO_LEFT:
      x = pbar->activity_pos;
      y = widget->style->ythickness;
      w = MAX (2, widget->allocation.width / pbar->activity_blocks);
      h = widget->allocation.height - 2 * widget->style->ythickness;
      break;

    case GTK_PROGRESS_TOP_TO_BOTTOM:
    case GTK_PROGRESS_BOTTOM_TO_TOP:
      x = widget->style->xthickness;
      y = pbar->activity_pos;
      w = widget->allocation.width - 2 * widget->style->xthickness;
      h = MAX (2, widget->allocation.height / pbar->activity_blocks);
      break;

    default:
      return;
      break;
    }

  gtk_paint_box (widget->style,
		 progress->offscreen_pixmap,
		 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
		 NULL, widget, "bar",
		 x, y, w, h);
}

static void
622 623 624
gtk_progress_bar_paint_continuous (GtkProgressBar            *pbar,
				   gint                       amount,
				   GtkProgressBarOrientation  orientation)
625 626 627 628 629 630
{
  GtkWidget *widget = GTK_WIDGET (pbar);
  gint x, y, w, h;

  if (amount <= 0)
    return;
631

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668
  switch (orientation)
    {
    case GTK_PROGRESS_LEFT_TO_RIGHT:
    case GTK_PROGRESS_RIGHT_TO_LEFT:
      w = amount;
      h = widget->allocation.height - widget->style->ythickness * 2;
      y = widget->style->ythickness;
      
      x = widget->style->xthickness;
      if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	x = widget->allocation.width - amount - x;
      break;
      
    case GTK_PROGRESS_TOP_TO_BOTTOM:
    case GTK_PROGRESS_BOTTOM_TO_TOP:
      w = widget->allocation.width - widget->style->xthickness * 2;
      h = amount;
      x = widget->style->xthickness;
      
      y = widget->style->ythickness;
      if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
	y = widget->allocation.height - amount - y;
      break;
      
    default:
      return;
      break;
    }
  
  gtk_paint_box (widget->style,
		 GTK_PROGRESS (pbar)->offscreen_pixmap,
		 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
		 NULL, widget, "bar",
		 x, y, w, h);
}

static void
669 670
gtk_progress_bar_paint_discrete (GtkProgressBar            *pbar,
				 GtkProgressBarOrientation  orientation)
671 672
{
  GtkWidget *widget = GTK_WIDGET (pbar);
673
  gint i;
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

  for (i = 0; i <= pbar->in_block; i++)
    {
      gint x, y, w, h, space;

      switch (orientation)
	{
	case GTK_PROGRESS_LEFT_TO_RIGHT:
	case GTK_PROGRESS_RIGHT_TO_LEFT:
	  space = widget->allocation.width - 2 * widget->style->xthickness;
	  
	  x = widget->style->xthickness + (i * space) / pbar->blocks;
	  y = widget->style->ythickness;
	  w = widget->style->xthickness + ((i + 1) * space) / pbar->blocks - x;
	  h = widget->allocation.height - 2 * widget->style->ythickness;

	  if (orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	    x = widget->allocation.width - w - x;
	  break;
	  
	case GTK_PROGRESS_TOP_TO_BOTTOM:
	case GTK_PROGRESS_BOTTOM_TO_TOP:
	  space = widget->allocation.height - 2 * widget->style->ythickness;
	  
	  x = widget->style->xthickness;
	  y = widget->style->ythickness + (i * space) / pbar->blocks;
	  w = widget->allocation.width - 2 * widget->style->xthickness;
	  h = widget->style->ythickness + ((i + 1) * space) / pbar->blocks - y;
	  
	  if (orientation == GTK_PROGRESS_BOTTOM_TO_TOP)
	    y = widget->allocation.height - h - y;
	  break;

	default:
	  return;
	  break;
	}
      
      gtk_paint_box (widget->style,
		     GTK_PROGRESS (pbar)->offscreen_pixmap,
		     GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
		     NULL, widget, "bar",
		     x, y, w, h);
    }
}

static void
721 722 723
gtk_progress_bar_paint_text (GtkProgressBar            *pbar,
			     gint			amount,
			     GtkProgressBarOrientation  orientation)
724 725 726 727
{
  GtkProgress *progress = GTK_PROGRESS (pbar);
  GtkWidget *widget = GTK_WIDGET (pbar);
  
728 729
  gint x;
  gint y;
730 731 732 733
  gchar *buf;
  GdkRectangle rect;
  PangoLayout *layout;
  PangoRectangle logical_rect;
734
  GdkRectangle prelight_clip, normal_clip;
735 736 737 738 739 740 741 742 743 744
  
  buf = gtk_progress_get_current_text (progress);
  
  layout = gtk_widget_create_pango_layout (widget, buf);
  pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
  
  x = widget->style->xthickness + 1 + 
    (widget->allocation.width - 2 * widget->style->xthickness -
     3 - logical_rect.width)
    * progress->x_align; 
745

746 747 748 749
  y = widget->style->ythickness + 1 +
    (widget->allocation.height - 2 * widget->style->ythickness -
     3 - logical_rect.height)
    * progress->y_align;
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783

  rect.x = widget->style->xthickness;
  rect.y = widget->style->ythickness;
  rect.width = widget->allocation.width - 2 * widget->style->xthickness;
  rect.height = widget->allocation.height - 2 * widget->style->ythickness;

  prelight_clip = normal_clip = rect;

  switch (orientation)
    {
    case GTK_PROGRESS_LEFT_TO_RIGHT:
      prelight_clip.width = amount;
      normal_clip.x += amount;
      normal_clip.width -= amount;
      break;
      
    case GTK_PROGRESS_RIGHT_TO_LEFT:
      normal_clip.width -= amount;
      prelight_clip.x += normal_clip.width;
      prelight_clip.width -= normal_clip.width;
      break;
       
    case GTK_PROGRESS_TOP_TO_BOTTOM:
      prelight_clip.height = amount;
      normal_clip.y += amount;
      normal_clip.height -= amount;
      break;
      
    case GTK_PROGRESS_BOTTOM_TO_TOP:
      normal_clip.height -= amount;
      prelight_clip.y += normal_clip.height;
      prelight_clip.height -= normal_clip.height;
      break;
    }
784 785 786
  
  gtk_paint_layout (widget->style,
		    progress->offscreen_pixmap,
787
		    GTK_STATE_PRELIGHT,
788
		    FALSE,
789
		    &prelight_clip,
790 791 792 793 794
		    widget,
		    "progressbar",
		    x, y,
		    layout);
  
795 796 797 798 799 800 801 802 803 804
  gtk_paint_layout (widget->style,
		    progress->offscreen_pixmap,
		    GTK_STATE_NORMAL,
		    FALSE,
		    &normal_clip,
		    widget,
		    "progressbar",
		    x, y,
		    layout);

805 806 807 808 809 810 811 812 813 814
  g_object_unref (layout);
  g_free (buf);
}

static void
gtk_progress_bar_paint (GtkProgress *progress)
{
  GtkProgressBar *pbar;
  GtkWidget *widget;

815
  GtkProgressBarOrientation orientation;
816 817 818 819 820 821

  g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));

  pbar = GTK_PROGRESS_BAR (progress);
  widget = GTK_WIDGET (progress);

822 823 824 825 826 827 828 829 830
  orientation = pbar->orientation;
  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
    {
      if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
	orientation = GTK_PROGRESS_RIGHT_TO_LEFT;
      else if (pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
    }
 
831 832
  if (progress->offscreen_pixmap)
    {
833 834 835 836 837 838 839 840
      gtk_paint_box (widget->style,
		     progress->offscreen_pixmap,
		     GTK_STATE_NORMAL, GTK_SHADOW_IN, 
		     NULL, widget, "trough",
		     0, 0,
		     widget->allocation.width,
		     widget->allocation.height);
      
841 842
      if (progress->activity_mode)
	{
843
	  gtk_progress_bar_paint_activity (pbar, orientation);
844
	}
845
      else
846
	{
847 848 849 850 851 852 853 854 855 856 857 858
	  gint amount;
	  gint space;
	  
	  if (orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
	      orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
	    space = widget->allocation.width - 2 * widget->style->xthickness;
	  else
	    space = widget->allocation.height - 2 * widget->style->ythickness;
	  
	  amount = space *
	    gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
	  
859
	  if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
860 861 862 863 864 865
	    {
	      gtk_progress_bar_paint_continuous (pbar, amount, orientation);

	      if (GTK_PROGRESS (pbar)->show_text)
		gtk_progress_bar_paint_text (pbar, amount, orientation);
	    }
866 867
	  else
	    gtk_progress_bar_paint_discrete (pbar, orientation);
868
	}
Elliot Lee's avatar
Elliot Lee committed
869 870 871
    }
}

872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933
static void
gtk_progress_bar_set_bar_style_internal (GtkProgressBar     *pbar,
					 GtkProgressBarStyle bar_style)
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));

  if (pbar->bar_style != bar_style)
    {
      pbar->bar_style = bar_style;

      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
	gtk_widget_queue_resize (GTK_WIDGET (pbar));

      g_object_notify (G_OBJECT (pbar), "bar_style");
    }
}

static void
gtk_progress_bar_set_discrete_blocks_internal (GtkProgressBar *pbar,
					       guint           blocks)
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
  g_return_if_fail (blocks > 1);

  if (pbar->blocks != blocks)
    {
      pbar->blocks = blocks;

      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
	gtk_widget_queue_resize (GTK_WIDGET (pbar));

      g_object_notify (G_OBJECT (pbar), "discrete_blocks");
    }
}

static void
gtk_progress_bar_set_activity_step_internal (GtkProgressBar *pbar,
					     guint           step)
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));

  if (pbar->activity_step != step)
    {
      pbar->activity_step = step;
      g_object_notify (G_OBJECT (pbar), "activity_step");
    }
}

static void
gtk_progress_bar_set_activity_blocks_internal (GtkProgressBar *pbar,
					       guint           blocks)
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
  g_return_if_fail (blocks > 1);

  if (pbar->activity_blocks != blocks)
    {
      pbar->activity_blocks = blocks;
      g_object_notify (G_OBJECT (pbar), "activity_blocks");
    }
}

934 935
/*******************************************************************/

936 937 938 939 940 941 942 943 944 945
/**
 * gtk_progress_bar_set_fraction:
 * @pbar: a #GtkProgressBar
 * @fraction: fraction of the task that's been completed
 * 
 * Causes the progress bar to "fill in" the given fraction
 * of the bar. The fraction should be between 0.0 and 1.0,
 * inclusive.
 * 
 **/
946 947
void
gtk_progress_bar_set_fraction (GtkProgressBar *pbar,
948
                               gdouble         fraction)
949 950 951 952 953 954 955 956 957 958 959
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));

  /* If we know the percentage, we don't want activity mode. */
  gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), FALSE);
  
  /* We use the deprecated GtkProgress interface internally.
   * Once everything's been deprecated for a good long time,
   * we can clean up all this code.
   */
  gtk_progress_set_percentage (GTK_PROGRESS (pbar), fraction);
960 961

  g_object_notify (G_OBJECT (pbar), "fraction");
962 963
}

964 965 966 967 968 969 970 971 972 973
/**
 * gtk_progress_bar_pulse:
 * @pbar: a #GtkProgressBar
 * 
 * Indicates that some progress is made, but you don't know how much.
 * Causes the progress bar to enter "activity mode," where a block
 * bounces back and forth. Each call to gtk_progress_bar_pulse()
 * causes the block to move by a little bit (the amount of movement
 * per pulse is determined by gtk_progress_bar_set_pulse_step()).
 **/
974 975 976 977 978 979 980 981 982 983 984 985
void
gtk_progress_bar_pulse (GtkProgressBar *pbar)
{  
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));

  /* If we don't know the percentage, we must want activity mode. */
  gtk_progress_set_activity_mode (GTK_PROGRESS (pbar), TRUE);

  /* Sigh. */
  gtk_progress_bar_real_update (GTK_PROGRESS (pbar));
}

986 987 988 989 990 991 992
/**
 * gtk_progress_bar_set_text:
 * @pbar: a #GtkProgressBar
 * @text: a UTF-8 string
 * 
 * Causes the given @text to appear superimposed on the progress bar.
 **/
993 994
void
gtk_progress_bar_set_text (GtkProgressBar *pbar,
995
                           const gchar    *text)
996 997 998
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
  
999 1000 1001
  gtk_progress_set_show_text (GTK_PROGRESS (pbar), text && *text);
  gtk_progress_set_format_string (GTK_PROGRESS (pbar), text);
  
1002 1003 1004 1005 1006
  /* We don't support formats in this interface, but turn
   * them back on for NULL, which should put us back to
   * the initial state.
   */
  GTK_PROGRESS (pbar)->use_text_format = (text == NULL);
1007
  
1008
  g_object_notify (G_OBJECT (pbar), "text");
1009 1010
}

1011 1012 1013 1014 1015 1016 1017 1018
/**
 * gtk_progress_bar_set_pulse_step:
 * @pbar: a #GtkProgressBar
 * @fraction: fraction between 0.0 and 1.0
 * 
 * Sets the fraction of total progress bar length to move the
 * bouncing block for each call to gtk_progress_bar_pulse().
 **/
1019 1020
void
gtk_progress_bar_set_pulse_step   (GtkProgressBar *pbar,
1021
                                   gdouble         fraction)
1022 1023 1024 1025
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
  
  pbar->pulse_fraction = fraction;
1026 1027

  g_object_notify (G_OBJECT (pbar), "pulse_step");
1028 1029
}

1030 1031
void
gtk_progress_bar_update (GtkProgressBar *pbar,
1032
			 gdouble         percentage)
Elliot Lee's avatar
Elliot Lee committed
1033
{
1034
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
Elliot Lee's avatar
Elliot Lee committed
1035

1036 1037 1038
  /* Use of gtk_progress_bar_update() is deprecated ! 
   * Use gtk_progress_bar_set_percentage ()
   */   
Elliot Lee's avatar
Elliot Lee committed
1039

1040 1041 1042
  gtk_progress_set_percentage (GTK_PROGRESS (pbar), percentage);
}

1043 1044 1045 1046 1047 1048 1049 1050
/**
 * gtk_progress_bar_set_orientation:
 * @pbar: a #GtkProgressBar
 * @orientation: orientation of the progress bar
 * 
 * Causes the progress bar to switch to a different orientation
 * (left-to-right, right-to-left, top-to-bottom, or bottom-to-top). 
 **/
1051 1052 1053 1054 1055 1056 1057
void
gtk_progress_bar_set_orientation (GtkProgressBar           *pbar,
				  GtkProgressBarOrientation orientation)
{
  g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));

  if (pbar->orientation != orientation)
Elliot Lee's avatar
Elliot Lee committed
1058
    {
1059
      pbar->orientation = orientation;
Elliot Lee's avatar
Elliot Lee committed
1060

1061 1062
      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
	gtk_widget_queue_resize (GTK_WIDGET (pbar));
1063

Alexander Larsson's avatar
Alexander Larsson committed
1064 1065
      g_object_notify (G_OBJECT (pbar), "orientation");
    }
1066 1067 1068 1069 1070 1071
}

/**
 * gtk_progress_bar_get_text:
 * @pbar: a #GtkProgressBar
 * 
1072 1073 1074 1075
 * Retrieves the text displayed superimposed on the progress bar,
 * if any, otherwise %NULL. The return value is a reference
 * to the text, not a copy of it, so will become invalid
 * if you change the text in the progress bar.
1076
 * 
Soren Sandmann's avatar
Soren Sandmann committed
1077 1078
 * Return value: text, or %NULL; this string is owned by the widget
 * and should not be modified or freed.
1079
 **/
1080
G_CONST_RETURN gchar*
1081 1082 1083 1084 1085 1086 1087
gtk_progress_bar_get_text (GtkProgressBar *pbar)
{
  g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), NULL);

  if (GTK_PROGRESS (pbar)->use_text_format)
    return NULL;
  else
1088
    return GTK_PROGRESS (pbar)->format;
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
}

/**
 * gtk_progress_bar_get_fraction:
 * @pbar: a #GtkProgressBar
 * 
 * Returns the current fraction of the task that's been completed.
 * 
 * Return value: a fraction from 0.0 to 1.0
 **/
1099
gdouble
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
gtk_progress_bar_get_fraction (GtkProgressBar *pbar)
{
  g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);

  return gtk_progress_get_current_percentage (GTK_PROGRESS (pbar));
}

/**
 * gtk_progress_bar_get_pulse_step:
 * @pbar: a #GtkProgressBar
 * 
 * Retrieves the pulse step set with gtk_progress_bar_set_pulse_step()
 * 
 * Return value: a fraction from 0.0 to 1.0
 **/
1115
gdouble
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136
gtk_progress_bar_get_pulse_step (GtkProgressBar *pbar)
{
  g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);

  return pbar->pulse_fraction;
}

/**
 * gtk_progress_bar_get_orientation:
 * @pbar: a #GtkProgressBar
 * 
 * Retrieves the current progress bar orientation.
 * 
 * Return value: orientation of the progress bar
 **/
GtkProgressBarOrientation
gtk_progress_bar_get_orientation (GtkProgressBar *pbar)
{
  g_return_val_if_fail (GTK_IS_PROGRESS_BAR (pbar), 0);

  return pbar->orientation;
Elliot Lee's avatar
Elliot Lee committed
1137 1138
}

Stefan Jeske's avatar