source: trunk/third/gtk/gtk/gtkprogress.c @ 14482

Revision 14482, 16.9 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 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.
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 * Library General Public License for more details.
13 *
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.
18 */
19
20/*
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/.
25 */
26
27#include <stdio.h>
28#include <math.h>
29#include <string.h>
30#include "gtkprogress.h"
31#include "gtksignal.h"
32
33#define EPSILON  1e-5
34
35enum {
36  ARG_0,
37  ARG_ACTIVITY_MODE,
38  ARG_SHOW_TEXT,
39  ARG_TEXT_XALIGN,
40  ARG_TEXT_YALIGN
41};
42
43
44static void gtk_progress_class_init      (GtkProgressClass *klass);
45static void gtk_progress_init            (GtkProgress      *progress);
46static void gtk_progress_set_arg         (GtkObject        *object,
47                                          GtkArg           *arg,
48                                          guint             arg_id);
49static void gtk_progress_get_arg         (GtkObject        *object,
50                                          GtkArg           *arg,
51                                          guint             arg_id);
52static void gtk_progress_destroy         (GtkObject        *object);
53static void gtk_progress_finalize        (GtkObject        *object);
54static void gtk_progress_realize         (GtkWidget        *widget);
55static gint gtk_progress_expose          (GtkWidget        *widget,
56                                          GdkEventExpose   *event);
57static void gtk_progress_size_allocate   (GtkWidget        *widget,
58                                          GtkAllocation    *allocation);
59static void gtk_progress_create_pixmap   (GtkProgress      *progress);
60
61
62static GtkWidgetClass *parent_class = NULL;
63
64
65GtkType
66gtk_progress_get_type (void)
67{
68  static GtkType progress_type = 0;
69
70  if (!progress_type)
71    {
72      static const GtkTypeInfo progress_info =
73      {
74        "GtkProgress",
75        sizeof (GtkProgress),
76        sizeof (GtkProgressClass),
77        (GtkClassInitFunc) gtk_progress_class_init,
78        (GtkObjectInitFunc) gtk_progress_init,
79        /* reserved_1 */ NULL,
80        /* reserved_2 */ NULL,
81        (GtkClassInitFunc) NULL
82      };
83
84      progress_type = gtk_type_unique (GTK_TYPE_WIDGET, &progress_info);
85    }
86
87  return progress_type;
88}
89
90static void
91gtk_progress_class_init (GtkProgressClass *class)
92{
93  GtkObjectClass *object_class;
94  GtkWidgetClass *widget_class;
95
96  object_class = (GtkObjectClass *) class;
97  widget_class = (GtkWidgetClass *) class;
98  parent_class = gtk_type_class (GTK_TYPE_WIDGET);
99
100  gtk_object_add_arg_type ("GtkProgress::activity_mode",
101                           GTK_TYPE_BOOL,
102                           GTK_ARG_READWRITE,
103                           ARG_ACTIVITY_MODE);
104  gtk_object_add_arg_type ("GtkProgress::show_text",
105                           GTK_TYPE_BOOL,
106                           GTK_ARG_READWRITE,
107                           ARG_SHOW_TEXT);
108  gtk_object_add_arg_type ("GtkProgress::text_xalign",
109                           GTK_TYPE_FLOAT,
110                           GTK_ARG_READWRITE,
111                           ARG_TEXT_XALIGN);
112  gtk_object_add_arg_type ("GtkProgress::text_yalign",
113                           GTK_TYPE_FLOAT,
114                           GTK_ARG_READWRITE,
115                           ARG_TEXT_YALIGN);
116
117  object_class->set_arg = gtk_progress_set_arg;
118  object_class->get_arg = gtk_progress_get_arg;
119  object_class->destroy = gtk_progress_destroy;
120  object_class->finalize = gtk_progress_finalize;
121
122  widget_class->realize = gtk_progress_realize;
123  widget_class->expose_event = gtk_progress_expose;
124  widget_class->size_allocate = gtk_progress_size_allocate;
125
126  /* to be overridden */
127  class->paint = NULL;
128  class->update = NULL;
129  class->act_mode_enter = NULL;
130}
131
132static void
133gtk_progress_set_arg (GtkObject      *object,
134                      GtkArg         *arg,
135                      guint           arg_id)
136{
137  GtkProgress *progress;
138 
139  progress = GTK_PROGRESS (object);
140
141  switch (arg_id)
142    {
143    case ARG_ACTIVITY_MODE:
144      gtk_progress_set_activity_mode (progress, GTK_VALUE_BOOL (*arg));
145      break;
146    case ARG_SHOW_TEXT:
147      gtk_progress_set_show_text (progress, GTK_VALUE_BOOL (*arg));
148      break;
149    case ARG_TEXT_XALIGN:
150      gtk_progress_set_text_alignment (progress, GTK_VALUE_FLOAT (*arg), progress->y_align);
151      break;
152    case ARG_TEXT_YALIGN:
153      gtk_progress_set_text_alignment (progress, progress->x_align, GTK_VALUE_FLOAT (*arg));
154      break;
155    default:
156      break;
157    }
158}
159
160static void
161gtk_progress_get_arg (GtkObject      *object,
162                      GtkArg         *arg,
163                      guint           arg_id)
164{
165  GtkProgress *progress;
166 
167  progress = GTK_PROGRESS (object);
168
169  switch (arg_id)
170    {
171    case ARG_ACTIVITY_MODE:
172      GTK_VALUE_BOOL (*arg) = (progress->activity_mode != 0);
173      break;
174    case ARG_SHOW_TEXT:
175      GTK_VALUE_BOOL (*arg) = (progress->show_text != 0);
176      break;
177    case ARG_TEXT_XALIGN:
178      GTK_VALUE_FLOAT (*arg) = progress->x_align;
179      break;
180    case ARG_TEXT_YALIGN:
181      GTK_VALUE_FLOAT (*arg) = progress->y_align;
182      break;
183    default:
184      arg->type = GTK_TYPE_INVALID;
185      break;
186    }
187}
188
189static void
190gtk_progress_init (GtkProgress *progress)
191{
192  progress->adjustment = NULL;
193  progress->offscreen_pixmap = NULL;
194  progress->format = g_strdup ("%P %%");
195  progress->x_align = 0.5;
196  progress->y_align = 0.5;
197  progress->show_text = FALSE;
198  progress->activity_mode = FALSE;
199}
200
201static void
202gtk_progress_realize (GtkWidget *widget)
203{
204  GtkProgress *progress;
205  GdkWindowAttr attributes;
206  gint attributes_mask;
207
208  g_return_if_fail (widget != NULL);
209  g_return_if_fail (GTK_IS_PROGRESS (widget));
210
211  progress = GTK_PROGRESS (widget);
212  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
213
214  attributes.window_type = GDK_WINDOW_CHILD;
215  attributes.x = widget->allocation.x;
216  attributes.y = widget->allocation.y;
217  attributes.width = widget->allocation.width;
218  attributes.height = widget->allocation.height;
219  attributes.wclass = GDK_INPUT_OUTPUT;
220  attributes.visual = gtk_widget_get_visual (widget);
221  attributes.colormap = gtk_widget_get_colormap (widget);
222  attributes.event_mask = gtk_widget_get_events (widget);
223  attributes.event_mask |= GDK_EXPOSURE_MASK;
224
225  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
226
227  widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
228                                   &attributes, attributes_mask);
229  gdk_window_set_user_data (widget->window, progress);
230
231  widget->style = gtk_style_attach (widget->style, widget->window);
232  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
233
234  gtk_progress_create_pixmap (progress);
235}
236
237static void
238gtk_progress_destroy (GtkObject *object)
239{
240  GtkProgress *progress;
241
242  g_return_if_fail (object != NULL);
243  g_return_if_fail (GTK_IS_PROGRESS (object));
244
245  progress = GTK_PROGRESS (object);
246
247  if (progress->adjustment)
248    gtk_signal_disconnect_by_data (GTK_OBJECT (progress->adjustment),
249                                   progress);
250
251  GTK_OBJECT_CLASS (parent_class)->destroy (object);
252}
253
254static void
255gtk_progress_finalize (GtkObject *object)
256{
257  GtkProgress *progress;
258
259  g_return_if_fail (object != NULL);
260  g_return_if_fail (GTK_IS_PROGRESS (object));
261
262  progress = GTK_PROGRESS (object);
263
264  if (progress->adjustment)
265    gtk_object_unref (GTK_OBJECT (GTK_PROGRESS (object)->adjustment));
266 
267  if (progress->offscreen_pixmap)
268    gdk_pixmap_unref (progress->offscreen_pixmap);
269
270  if (progress->format)
271    g_free (progress->format);
272
273  GTK_OBJECT_CLASS (parent_class)->finalize (object);
274}
275
276static gint
277gtk_progress_expose (GtkWidget      *widget,
278                     GdkEventExpose *event)
279{
280  g_return_val_if_fail (widget != NULL, FALSE);
281  g_return_val_if_fail (GTK_IS_PROGRESS (widget), FALSE);
282  g_return_val_if_fail (event != NULL, FALSE);
283
284  if (GTK_WIDGET_DRAWABLE (widget))
285    gdk_draw_pixmap (widget->window,
286                     widget->style->black_gc,
287                     GTK_PROGRESS (widget)->offscreen_pixmap,
288                     event->area.x, event->area.y,
289                     event->area.x, event->area.y,
290                     event->area.width,
291                     event->area.height);
292
293  return FALSE;
294}
295
296static void
297gtk_progress_size_allocate (GtkWidget     *widget,
298                            GtkAllocation *allocation)
299{
300  g_return_if_fail (widget != NULL);
301  g_return_if_fail (GTK_IS_PROGRESS (widget));
302  g_return_if_fail (allocation != NULL);
303
304  widget->allocation = *allocation;
305
306  if (GTK_WIDGET_REALIZED (widget))
307    {
308      gdk_window_move_resize (widget->window,
309                              allocation->x, allocation->y,
310                              allocation->width, allocation->height);
311
312      gtk_progress_create_pixmap (GTK_PROGRESS (widget));
313    }
314}
315
316static void
317gtk_progress_create_pixmap (GtkProgress *progress)
318{
319  GtkWidget *widget;
320
321  g_return_if_fail (progress != NULL);
322  g_return_if_fail (GTK_IS_PROGRESS (progress));
323
324  if (GTK_WIDGET_REALIZED (progress))
325    {
326      widget = GTK_WIDGET (progress);
327
328      if (progress->offscreen_pixmap)
329        gdk_pixmap_unref (progress->offscreen_pixmap);
330
331      progress->offscreen_pixmap = gdk_pixmap_new (widget->window,
332                                                   widget->allocation.width,
333                                                   widget->allocation.height,
334                                                   -1);
335      GTK_PROGRESS_CLASS (GTK_OBJECT (progress)->klass)->paint (progress);
336    }
337}
338
339static void
340gtk_progress_value_changed (GtkAdjustment *adjustment,
341                            GtkProgress   *progress)
342{
343  GTK_PROGRESS_CLASS (GTK_OBJECT (progress)->klass)->update (progress);
344}
345
346static gchar *
347gtk_progress_build_string (GtkProgress *progress,
348                           gfloat       value,
349                           gfloat       percentage)
350{
351  gchar buf[256] = { 0 };
352  gchar tmp[256] = { 0 };
353  gchar *src;
354  gchar *dest;
355  gchar fmt[10];
356
357  src = progress->format;
358  dest = buf;
359 
360  while (src && *src)
361    {
362      if (*src != '%')
363        {
364          *dest = *src;
365          dest++;
366        }
367      else
368        {
369          gchar c;
370          gint digits;
371
372          c = *(src + sizeof(gchar));
373          digits = 0;
374
375          if (c >= '0' && c <= '2')
376            {
377              digits = (gint) (c - '0');
378              src++;
379              c = *(src + sizeof(gchar));
380            }
381
382          switch (c)
383            {
384            case '%':
385              *dest = '%';
386              src++;
387              dest++;
388              break;
389            case 'p':
390            case 'P':
391              if (digits)
392                {
393                  sprintf (fmt, "%%.%df", digits);
394                  sprintf (tmp, fmt, 100 * percentage);
395                }
396              else
397                sprintf (tmp, "%.0f", 100 * percentage);
398              strcat (buf, tmp);
399              dest = &(buf[strlen (buf)]);
400              src++;
401              break;
402            case 'v':
403            case 'V':
404              if (digits)
405                {
406                  sprintf (fmt, "%%.%df", digits);
407                  sprintf (tmp, fmt, value);
408                }
409              else
410                sprintf (tmp, "%.0f", value);
411              strcat (buf, tmp);
412              dest = &(buf[strlen (buf)]);
413              src++;
414              break;
415            case 'l':
416            case 'L':
417              if (digits)
418                {
419                  sprintf (fmt, "%%.%df", digits);
420                  sprintf (tmp, fmt, progress->adjustment->lower);
421                }
422              else
423                sprintf (tmp, "%.0f", progress->adjustment->lower);
424              strcat (buf, tmp);
425              dest = &(buf[strlen (buf)]);
426              src++;
427              break;
428            case 'u':
429            case 'U':
430              if (digits)
431                {
432                  sprintf (fmt, "%%.%df", digits);
433                  sprintf (tmp, fmt, progress->adjustment->upper);
434                }
435              else
436                sprintf (tmp, "%.0f", progress->adjustment->upper);
437              strcat (buf, tmp);
438              dest = &(buf[strlen (buf)]);
439              src++;
440              break;
441            default:
442              break;
443            }
444        }
445      src++;
446    }
447
448  return g_strdup (buf);
449}
450
451/***************************************************************/
452
453void
454gtk_progress_set_adjustment (GtkProgress   *progress,
455                             GtkAdjustment *adjustment)
456{
457  g_return_if_fail (progress != NULL);
458  g_return_if_fail (GTK_IS_PROGRESS (progress));
459  if (adjustment)
460    g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
461  else
462    adjustment = (GtkAdjustment*) gtk_adjustment_new (0, 0, 100, 0, 0, 0);
463
464  if (progress->adjustment != adjustment)
465    {
466      if (progress->adjustment)
467        {
468          gtk_signal_disconnect_by_data (GTK_OBJECT (progress->adjustment),
469                                         (gpointer) progress);
470          gtk_object_unref (GTK_OBJECT (progress->adjustment));
471        }
472      progress->adjustment = adjustment;
473      if (adjustment)
474        {
475          gtk_object_ref (GTK_OBJECT (adjustment));
476          gtk_object_sink (GTK_OBJECT (adjustment));
477          gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
478                              (GtkSignalFunc) gtk_progress_value_changed,
479                              (gpointer) progress);
480        }
481    }
482}
483
484void
485gtk_progress_configure (GtkProgress *progress,
486                        gfloat value,
487                        gfloat min,
488                        gfloat max)
489{
490  GtkAdjustment *adj;
491  gboolean changed = FALSE;
492
493  g_return_if_fail (progress != NULL);
494  g_return_if_fail (GTK_IS_PROGRESS (progress));
495  g_return_if_fail (min <= max);
496  g_return_if_fail (value >= min && value <= max);
497
498  adj = progress->adjustment;
499
500  if (fabs (adj->lower - min) > EPSILON || fabs (adj->upper - max) > EPSILON)
501    changed = TRUE;
502
503  adj->value = value;
504  adj->lower = min;
505  adj->upper = max;
506
507  gtk_signal_emit_by_name (GTK_OBJECT (adj), "value_changed");
508  if (changed)
509    gtk_signal_emit_by_name (GTK_OBJECT (progress->adjustment), "changed");
510}
511
512void
513gtk_progress_set_percentage (GtkProgress *progress,
514                             gfloat       percentage)
515{
516  g_return_if_fail (progress != NULL);
517  g_return_if_fail (GTK_IS_PROGRESS (progress));
518  g_return_if_fail (percentage >= 0 && percentage <= 1.0);
519
520  gtk_progress_set_value (progress, progress->adjustment->lower + percentage *
521                 (progress->adjustment->upper - progress->adjustment->lower));
522}
523
524gfloat
525gtk_progress_get_current_percentage (GtkProgress *progress)
526{
527  g_return_val_if_fail (progress != NULL, 0);
528  g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
529
530  return (progress->adjustment->value - progress->adjustment->lower) /
531    (progress->adjustment->upper - progress->adjustment->lower);
532}
533
534gfloat
535gtk_progress_get_percentage_from_value (GtkProgress *progress,
536                                        gfloat       value)
537{
538  g_return_val_if_fail (progress != NULL, 0);
539  g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
540
541  if (value >= progress->adjustment->lower &&
542      value <= progress->adjustment->upper)
543    return (value - progress->adjustment->lower) /
544      (progress->adjustment->upper - progress->adjustment->lower);
545  else
546    return 0.0;
547}
548
549void
550gtk_progress_set_value (GtkProgress *progress,
551                        gfloat       value)
552{
553  g_return_if_fail (progress != NULL);
554  g_return_if_fail (GTK_IS_PROGRESS (progress));
555
556  if (fabs (progress->adjustment->value - value) > EPSILON)
557    gtk_adjustment_set_value (progress->adjustment, value);
558}
559
560gfloat
561gtk_progress_get_value (GtkProgress *progress)
562{
563  g_return_val_if_fail (progress != NULL, 0);
564  g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
565
566  return progress->adjustment->value;
567}
568
569void
570gtk_progress_set_show_text (GtkProgress *progress,
571                            gint        show_text)
572{
573  g_return_if_fail (progress != NULL);
574  g_return_if_fail (GTK_IS_PROGRESS (progress));
575
576  if (progress->show_text != show_text)
577    {
578      progress->show_text = show_text;
579
580      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
581        gtk_widget_queue_resize (GTK_WIDGET (progress));
582    }
583}
584
585void
586gtk_progress_set_text_alignment (GtkProgress *progress,
587                                 gfloat       x_align,
588                                 gfloat       y_align)
589{
590  g_return_if_fail (progress != NULL);
591  g_return_if_fail (GTK_IS_PROGRESS (progress));
592  g_return_if_fail (x_align >= 0.0 && x_align <= 1.0);
593  g_return_if_fail (y_align >= 0.0 && y_align <= 1.0);
594
595  if (progress->x_align != x_align || progress->y_align != y_align)
596    {
597      progress->x_align = x_align;
598      progress->y_align = y_align;
599
600      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
601        gtk_widget_queue_resize (GTK_WIDGET (progress));
602    }
603}
604
605void
606gtk_progress_set_format_string (GtkProgress *progress,
607                                const gchar *format)
608{
609  g_return_if_fail (progress != NULL);
610  g_return_if_fail (GTK_IS_PROGRESS (progress));
611
612  if (format)
613    {
614      if (progress->format)
615        g_free (progress->format);
616      progress->format = g_strdup (format);
617
618      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
619        gtk_widget_queue_resize (GTK_WIDGET (progress));
620    }
621}
622
623gchar *
624gtk_progress_get_current_text (GtkProgress *progress)
625{
626  g_return_val_if_fail (progress != NULL, 0);
627  g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
628
629  return gtk_progress_build_string (progress, progress->adjustment->value,
630                    gtk_progress_get_current_percentage (progress));
631}
632
633gchar *
634gtk_progress_get_text_from_value (GtkProgress *progress,
635                                  gfloat       value)
636{
637  g_return_val_if_fail (progress != NULL, 0);
638  g_return_val_if_fail (GTK_IS_PROGRESS (progress), 0);
639
640  return gtk_progress_build_string (progress, value,
641                    gtk_progress_get_percentage_from_value (progress, value));
642}
643
644void
645gtk_progress_set_activity_mode (GtkProgress *progress,
646                                guint        activity_mode)
647{
648  g_return_if_fail (progress != NULL);
649  g_return_if_fail (GTK_IS_PROGRESS (progress));
650
651  if (progress->activity_mode != (activity_mode != 0))
652    {
653      progress->activity_mode = (activity_mode != 0);
654
655      if (progress->activity_mode)
656        GTK_PROGRESS_CLASS
657          (GTK_OBJECT (progress)->klass)->act_mode_enter (progress);
658
659      if (GTK_WIDGET_DRAWABLE (GTK_WIDGET (progress)))
660        gtk_widget_queue_resize (GTK_WIDGET (progress));
661    }
662}
Note: See TracBrowser for help on using the repository browser.