1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
21 * Modified by the GTK+ Team and others 1997-1999. 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/.
37 #include "gtkprogressbar.h"
38 #include "gtksignal.h"
41 #define MIN_HORIZONTAL_BAR_WIDTH 150
42 #define MIN_HORIZONTAL_BAR_HEIGHT 20
43 #define MIN_VERTICAL_BAR_WIDTH 22
44 #define MIN_VERTICAL_BAR_HEIGHT 80
45 #define MAX_TEXT_LENGTH 80
46 #define TEXT_SPACING 2
58 static void gtk_progress_bar_class_init (GtkProgressBarClass *klass);
59 static void gtk_progress_bar_init (GtkProgressBar *pbar);
60 static void gtk_progress_bar_set_arg (GtkObject *object,
63 static void gtk_progress_bar_get_arg (GtkObject *object,
66 static void gtk_progress_bar_size_request (GtkWidget *widget,
67 GtkRequisition *requisition);
68 static void gtk_progress_bar_real_update (GtkProgress *progress);
69 static void gtk_progress_bar_paint (GtkProgress *progress);
70 static void gtk_progress_bar_act_mode_enter (GtkProgress *progress);
74 gtk_progress_bar_get_type (void)
76 static GtkType progress_bar_type = 0;
78 if (!progress_bar_type)
80 static const GtkTypeInfo progress_bar_info =
83 sizeof (GtkProgressBar),
84 sizeof (GtkProgressBarClass),
85 (GtkClassInitFunc) gtk_progress_bar_class_init,
86 (GtkObjectInitFunc) gtk_progress_bar_init,
87 /* reserved_1 */ NULL,
88 /* reserved_2 */ NULL,
89 (GtkClassInitFunc) NULL
92 progress_bar_type = gtk_type_unique (GTK_TYPE_PROGRESS, &progress_bar_info);
95 return progress_bar_type;
99 gtk_progress_bar_class_init (GtkProgressBarClass *class)
101 GtkObjectClass *object_class;
102 GtkWidgetClass *widget_class;
103 GtkProgressClass *progress_class;
105 object_class = (GtkObjectClass *) class;
106 widget_class = (GtkWidgetClass *) class;
107 progress_class = (GtkProgressClass *) class;
109 gtk_object_add_arg_type ("GtkProgressBar::adjustment",
113 gtk_object_add_arg_type ("GtkProgressBar::orientation",
114 GTK_TYPE_PROGRESS_BAR_ORIENTATION,
117 gtk_object_add_arg_type ("GtkProgressBar::bar_style",
118 GTK_TYPE_PROGRESS_BAR_STYLE,
121 gtk_object_add_arg_type ("GtkProgressBar::activity_step",
125 gtk_object_add_arg_type ("GtkProgressBar::activity_blocks",
128 ARG_ACTIVITY_BLOCKS);
129 gtk_object_add_arg_type ("GtkProgressBar::discrete_blocks",
132 ARG_DISCRETE_BLOCKS);
134 object_class->set_arg = gtk_progress_bar_set_arg;
135 object_class->get_arg = gtk_progress_bar_get_arg;
137 widget_class->size_request = gtk_progress_bar_size_request;
139 progress_class->paint = gtk_progress_bar_paint;
140 progress_class->update = gtk_progress_bar_real_update;
141 progress_class->act_mode_enter = gtk_progress_bar_act_mode_enter;
145 gtk_progress_bar_init (GtkProgressBar *pbar)
147 pbar->bar_style = GTK_PROGRESS_CONTINUOUS;
150 pbar->orientation = GTK_PROGRESS_LEFT_TO_RIGHT;
151 pbar->activity_pos = 0;
152 pbar->activity_dir = 1;
153 pbar->activity_step = 3;
154 pbar->activity_blocks = 5;
158 gtk_progress_bar_set_arg (GtkObject *object,
162 GtkProgressBar *pbar;
164 pbar = GTK_PROGRESS_BAR (object);
169 gtk_progress_set_adjustment (GTK_PROGRESS (pbar), GTK_VALUE_POINTER (*arg));
171 case ARG_ORIENTATION:
172 gtk_progress_bar_set_orientation (pbar, GTK_VALUE_ENUM (*arg));
175 gtk_progress_bar_set_bar_style (pbar, GTK_VALUE_ENUM (*arg));
177 case ARG_ACTIVITY_STEP:
178 gtk_progress_bar_set_activity_step (pbar, GTK_VALUE_UINT (*arg));
180 case ARG_ACTIVITY_BLOCKS:
181 gtk_progress_bar_set_activity_blocks (pbar, GTK_VALUE_UINT (*arg));
183 case ARG_DISCRETE_BLOCKS:
184 gtk_progress_bar_set_discrete_blocks (pbar, GTK_VALUE_UINT (*arg));
192 gtk_progress_bar_get_arg (GtkObject *object,
196 GtkProgressBar *pbar;
198 pbar = GTK_PROGRESS_BAR (object);
203 GTK_VALUE_POINTER (*arg) = GTK_PROGRESS (pbar)->adjustment;
205 case ARG_ORIENTATION:
206 GTK_VALUE_ENUM (*arg) = pbar->orientation;
209 GTK_VALUE_ENUM (*arg) = pbar->bar_style;
211 case ARG_ACTIVITY_STEP:
212 GTK_VALUE_UINT (*arg) = pbar->activity_step;
214 case ARG_ACTIVITY_BLOCKS:
215 GTK_VALUE_UINT (*arg) = pbar->activity_blocks;
217 case ARG_DISCRETE_BLOCKS:
218 GTK_VALUE_UINT (*arg) = pbar->blocks;
221 arg->type = GTK_TYPE_INVALID;
227 gtk_progress_bar_new (void)
231 pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR, NULL);
237 gtk_progress_bar_new_with_adjustment (GtkAdjustment *adjustment)
241 g_return_val_if_fail (adjustment != NULL, NULL);
242 g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
244 pbar = gtk_widget_new (GTK_TYPE_PROGRESS_BAR,
245 "adjustment", adjustment,
252 gtk_progress_bar_real_update (GtkProgress *progress)
254 GtkProgressBar *pbar;
257 g_return_if_fail (progress != NULL);
258 g_return_if_fail (GTK_IS_PROGRESS (progress));
260 pbar = GTK_PROGRESS_BAR (progress);
261 widget = GTK_WIDGET (progress);
263 if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS ||
264 GTK_PROGRESS (pbar)->activity_mode)
266 if (GTK_PROGRESS (pbar)->activity_mode)
270 /* advance the block */
272 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
273 pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
275 size = MAX (2, widget->allocation.width / pbar->activity_blocks);
277 if (pbar->activity_dir == 0)
279 pbar->activity_pos += pbar->activity_step;
280 if (pbar->activity_pos + size >=
281 widget->allocation.width -
282 widget->style->klass->xthickness)
284 pbar->activity_pos = widget->allocation.width -
285 widget->style->klass->xthickness - size;
286 pbar->activity_dir = 1;
291 pbar->activity_pos -= pbar->activity_step;
292 if (pbar->activity_pos <= widget->style->klass->xthickness)
294 pbar->activity_pos = widget->style->klass->xthickness;
295 pbar->activity_dir = 0;
301 size = MAX (2, widget->allocation.height / pbar->activity_blocks);
303 if (pbar->activity_dir == 0)
305 pbar->activity_pos += pbar->activity_step;
306 if (pbar->activity_pos + size >=
307 widget->allocation.height -
308 widget->style->klass->ythickness)
310 pbar->activity_pos = widget->allocation.height -
311 widget->style->klass->ythickness - size;
312 pbar->activity_dir = 1;
317 pbar->activity_pos -= pbar->activity_step;
318 if (pbar->activity_pos <= widget->style->klass->ythickness)
320 pbar->activity_pos = widget->style->klass->ythickness;
321 pbar->activity_dir = 0;
326 gtk_progress_bar_paint (progress);
327 gtk_widget_queue_draw (GTK_WIDGET (progress));
333 in_block = -1 + (gint)(gtk_progress_get_current_percentage (progress) *
334 (gfloat)pbar->blocks);
336 if (pbar->in_block != in_block)
338 pbar->in_block = in_block;
339 gtk_progress_bar_paint (progress);
340 gtk_widget_queue_draw (GTK_WIDGET (progress));
346 gtk_progress_bar_size_request (GtkWidget *widget,
347 GtkRequisition *requisition)
349 GtkProgress *progress;
350 GtkProgressBar *pbar;
353 g_return_if_fail (widget != NULL);
354 g_return_if_fail (GTK_IS_PROGRESS_BAR (widget));
355 g_return_if_fail (requisition != NULL);
357 progress = GTK_PROGRESS (widget);
358 pbar = GTK_PROGRESS_BAR (widget);
360 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
361 pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
363 if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
365 buf = gtk_progress_get_text_from_value (progress,
366 progress->adjustment->upper);
368 requisition->width = MAX (MIN_HORIZONTAL_BAR_WIDTH,
369 2 * widget->style->klass->xthickness + 3 +
370 gdk_text_width (widget->style->font,
374 requisition->height = MAX (MIN_HORIZONTAL_BAR_HEIGHT,
375 2 * widget->style->klass->ythickness + 3 +
376 gdk_text_height (widget->style->font,
383 requisition->width = MIN_HORIZONTAL_BAR_WIDTH;
384 requisition->height = MIN_HORIZONTAL_BAR_HEIGHT;
389 if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
391 buf = gtk_progress_get_text_from_value (progress,
392 progress->adjustment->upper);
394 requisition->width = MAX (MIN_VERTICAL_BAR_WIDTH,
395 2 * widget->style->klass->xthickness + 3 +
396 gdk_text_width (widget->style->font,
400 requisition->height = MAX (MIN_VERTICAL_BAR_HEIGHT,
401 2 * widget->style->klass->ythickness + 3 +
402 gdk_text_height (widget->style->font,
409 requisition->width = MIN_VERTICAL_BAR_WIDTH;
410 requisition->height = MIN_VERTICAL_BAR_HEIGHT;
416 gtk_progress_bar_act_mode_enter (GtkProgress *progress)
418 GtkProgressBar *pbar;
422 pbar = GTK_PROGRESS_BAR (progress);
423 widget = GTK_WIDGET (progress);
425 /* calculate start pos */
427 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
428 pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
430 size = MAX (2, widget->allocation.width / pbar->activity_blocks);
432 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT)
434 pbar->activity_pos = widget->style->klass->xthickness;
435 pbar->activity_dir = 0;
439 pbar->activity_pos = widget->allocation.width -
440 widget->style->klass->xthickness - (widget->allocation.height -
441 widget->style->klass->ythickness * 2);
442 pbar->activity_dir = 1;
447 size = MAX (2, widget->allocation.height / pbar->activity_blocks);
449 if (pbar->orientation == GTK_PROGRESS_TOP_TO_BOTTOM)
451 pbar->activity_pos = widget->style->klass->ythickness;
452 pbar->activity_dir = 0;
456 pbar->activity_pos = widget->allocation.height -
457 widget->style->klass->ythickness - (widget->allocation.width -
458 widget->style->klass->xthickness * 2);
459 pbar->activity_dir = 1;
465 gtk_progress_bar_paint (GtkProgress *progress)
467 GtkProgressBar *pbar;
470 gint block_delta = 0;
478 g_return_if_fail (progress != NULL);
479 g_return_if_fail (GTK_IS_PROGRESS_BAR (progress));
481 pbar = GTK_PROGRESS_BAR (progress);
482 widget = GTK_WIDGET (progress);
484 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
485 pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
486 space = widget->allocation.width -
487 2 * widget->style->klass->xthickness;
489 space = widget->allocation.height -
490 2 * widget->style->klass->ythickness;
492 percentage = gtk_progress_get_current_percentage (progress);
494 if (progress->offscreen_pixmap)
496 gtk_paint_box (widget->style,
497 progress->offscreen_pixmap,
498 GTK_STATE_NORMAL, GTK_SHADOW_IN,
499 NULL, widget, "trough",
501 widget->allocation.width,
502 widget->allocation.height);
504 if (progress->activity_mode)
506 if (pbar->orientation == GTK_PROGRESS_LEFT_TO_RIGHT ||
507 pbar->orientation == GTK_PROGRESS_RIGHT_TO_LEFT)
509 size = MAX (2, widget->allocation.width / pbar->activity_blocks);
511 gtk_paint_box (widget->style,
512 progress->offscreen_pixmap,
513 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
516 widget->style->klass->ythickness,
518 widget->allocation.height - widget->style->klass->ythickness * 2);
523 size = MAX (2, widget->allocation.height / pbar->activity_blocks);
525 gtk_paint_box (widget->style,
526 progress->offscreen_pixmap,
527 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
529 widget->style->klass->xthickness,
531 widget->allocation.width - widget->style->klass->xthickness * 2,
537 amount = percentage * space;
541 switch (pbar->orientation)
544 case GTK_PROGRESS_LEFT_TO_RIGHT:
546 if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
548 gtk_paint_box (widget->style,
549 progress->offscreen_pixmap,
550 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
552 widget->style->klass->xthickness,
553 widget->style->klass->ythickness,
555 widget->allocation.height - widget->style->klass->ythickness * 2);
559 x = widget->style->klass->xthickness;
561 for (i = 0; i <= pbar->in_block; i++)
563 block_delta = (((i + 1) * space) / pbar->blocks)
564 - ((i * space) / pbar->blocks);
566 gtk_paint_box (widget->style,
567 progress->offscreen_pixmap,
568 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
571 widget->style->klass->ythickness,
573 widget->allocation.height - widget->style->klass->ythickness * 2);
580 case GTK_PROGRESS_RIGHT_TO_LEFT:
582 if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
584 gtk_paint_box (widget->style,
585 progress->offscreen_pixmap,
586 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
588 widget->allocation.width -
589 widget->style->klass->xthickness - amount,
590 widget->style->klass->ythickness,
592 widget->allocation.height -
593 widget->style->klass->ythickness * 2);
597 x = widget->allocation.width -
598 widget->style->klass->xthickness;
600 for (i = 0; i <= pbar->in_block; i++)
602 block_delta = (((i + 1) * space) / pbar->blocks) -
603 ((i * space) / pbar->blocks);
607 gtk_paint_box (widget->style,
608 progress->offscreen_pixmap,
609 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
612 widget->style->klass->ythickness,
614 widget->allocation.height -
615 widget->style->klass->ythickness * 2);
620 case GTK_PROGRESS_BOTTOM_TO_TOP:
622 if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
624 gtk_paint_box (widget->style,
625 progress->offscreen_pixmap,
626 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
628 widget->style->klass->xthickness,
629 widget->allocation.height -
630 widget->style->klass->ythickness - amount,
631 widget->allocation.width -
632 widget->style->klass->xthickness * 2,
637 y = widget->allocation.height -
638 widget->style->klass->ythickness;
640 for (i = 0; i <= pbar->in_block; i++)
642 block_delta = (((i + 1) * space) / pbar->blocks) -
643 ((i * space) / pbar->blocks);
647 gtk_paint_box (widget->style,
648 progress->offscreen_pixmap,
649 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
651 widget->style->klass->xthickness,
653 widget->allocation.width -
654 widget->style->klass->xthickness * 2,
660 case GTK_PROGRESS_TOP_TO_BOTTOM:
662 if (pbar->bar_style == GTK_PROGRESS_CONTINUOUS)
664 gtk_paint_box (widget->style,
665 progress->offscreen_pixmap,
666 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
668 widget->style->klass->xthickness,
669 widget->style->klass->ythickness,
670 widget->allocation.width -
671 widget->style->klass->xthickness * 2,
676 y = widget->style->klass->ythickness;
678 for (i = 0; i <= pbar->in_block; i++)
681 block_delta = (((i + 1) * space) / pbar->blocks)
682 - ((i * space) / pbar->blocks);
684 gtk_paint_box (widget->style,
685 progress->offscreen_pixmap,
686 GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
688 widget->style->klass->xthickness,
690 widget->allocation.width -
691 widget->style->klass->xthickness * 2,
704 if (progress->show_text && pbar->bar_style != GTK_PROGRESS_DISCRETE)
711 buf = gtk_progress_get_current_text (progress);
713 x = widget->style->klass->xthickness + 1 +
714 (widget->allocation.width - 2 * widget->style->klass->xthickness -
715 3 - gdk_text_width (widget->style->font, buf, strlen (buf)))
718 y = widget->style->font->ascent + 1 +
719 (widget->allocation.height - 2 * widget->style->klass->ythickness -
720 3 - gdk_text_height (widget->style->font, buf, strlen (buf)))
723 rect.x = widget->style->klass->xthickness + 1;
724 rect.y = widget->style->klass->ythickness + 1;
725 rect.width = widget->allocation.width -
726 2 * widget->style->klass->xthickness - 3;
727 rect.height = widget->allocation.height -
728 2 * widget->style->klass->ythickness - 3;
730 gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state],
733 gdk_draw_text (progress->offscreen_pixmap, widget->style->font,
734 widget->style->fg_gc[widget->state],
735 x, y, buf, strlen (buf));
737 gdk_gc_set_clip_rectangle (widget->style->fg_gc[widget->state],
744 /*******************************************************************/
747 gtk_progress_bar_update (GtkProgressBar *pbar,
750 g_return_if_fail (pbar != NULL);
751 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
753 /***********************************************************************
754 * Use of gtk_progress_bar_update() is deprecated ! *
755 * Use gtk_progress_set_value or gtk_progress_set_percentage instead. *
756 ***********************************************************************/
758 gtk_progress_set_percentage (GTK_PROGRESS (pbar), percentage);
762 gtk_progress_bar_set_orientation (GtkProgressBar *pbar,
763 GtkProgressBarOrientation orientation)
765 g_return_if_fail (pbar != NULL);
766 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
768 if (pbar->orientation != orientation)
770 pbar->orientation = orientation;
772 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
773 gtk_widget_queue_resize (GTK_WIDGET (pbar));
778 gtk_progress_bar_set_bar_style (GtkProgressBar *pbar,
779 GtkProgressBarStyle bar_style)
781 g_return_if_fail (pbar != NULL);
782 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
784 if (pbar->bar_style != bar_style)
786 pbar->bar_style = bar_style;
788 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
789 gtk_widget_queue_resize (GTK_WIDGET (pbar));
794 gtk_progress_bar_set_discrete_blocks (GtkProgressBar *pbar,
797 g_return_if_fail (pbar != NULL);
798 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
799 g_return_if_fail (blocks > 1);
801 if (pbar->blocks != blocks)
803 pbar->blocks = blocks;
805 if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (pbar)))
806 gtk_widget_queue_resize (GTK_WIDGET (pbar));
811 gtk_progress_bar_set_activity_step (GtkProgressBar *pbar,
814 g_return_if_fail (pbar != NULL);
815 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
817 if (pbar->activity_step != step)
818 pbar->activity_step = step;
822 gtk_progress_bar_set_activity_blocks (GtkProgressBar *pbar,
825 g_return_if_fail (pbar != NULL);
826 g_return_if_fail (GTK_IS_PROGRESS_BAR (pbar));
827 g_return_if_fail (blocks > 1);
829 if (pbar->activity_blocks != blocks)
830 pbar->activity_blocks = blocks;