dcf600e9dd8ebbcf2385aef04c6dc75148b822cd
[geeqie.git] / src / ui_spinner.c
1 /*
2  * (SLIK) SimpLIstic sKin functions
3  * (C) 2004 John Ellis
4  *
5  * Author: John Ellis
6  *
7  * This software is released under the GNU General Public License (GNU GPL).
8  * Please read the included file COPYING for more information.
9  * This software comes with no warranty of any kind, use at your own risk!
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #  include "config.h"
14 #endif
15 #include "intl.h"
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <gtk/gtk.h>
22
23 #include "ui_spinner.h"
24
25 #include "ui_icons.h"
26 #include "ui_fileops.h"
27
28
29 #define SPINNER_FRAMES 19
30
31
32 /*
33  *-----------------------------------------------------------------------------
34  * spinner utility
35  *-----------------------------------------------------------------------------
36  */
37
38 typedef struct _SpinnerData SpinnerData;
39 struct _SpinnerData {
40         GtkWidget *image;
41         GList *list;            /* list of pixbufs */
42         gint frame;
43         gint timer_id;
44 };
45
46 static void spinner_set_frame(SpinnerData *sp, gint frame)
47 {
48         GdkPixbuf *pb;
49
50         pb = g_list_nth_data(sp->list, frame);
51         if (pb) gtk_image_set_from_pixbuf(GTK_IMAGE(sp->image), pb);
52
53         sp->frame = frame;
54 }
55
56 static void spinner_increment_frame(SpinnerData *sp)
57 {
58         sp->frame++;
59         if (sp->frame >= g_list_length(sp->list)) sp->frame = 1;
60         spinner_set_frame(sp, sp->frame);
61 }
62
63 static gboolean spinner_loop_cb(gpointer data)
64 {
65         SpinnerData *sp = data;
66
67         if (sp->list) spinner_increment_frame(sp);
68
69         return TRUE;
70 }
71
72 static void spinner_set_timeout(SpinnerData *sp, gint interval)
73 {
74         if (!sp) return;
75
76         if (sp->timer_id != -1)
77                 {
78                 g_source_remove(sp->timer_id);
79                 sp->timer_id = -1;
80                 }
81
82         if (interval > 0)
83                 {
84                 sp->timer_id = g_timeout_add(interval, spinner_loop_cb, sp);
85                 }
86         else if (interval < 0)
87                 {
88                 spinner_set_frame(sp, 0);
89                 }
90
91         gtk_widget_set_sensitive(sp->image, (interval >= 0));
92 }
93
94 static void spinner_destroy_cb(GtkWidget *widget, gpointer data)
95 {
96         SpinnerData *sp = data;
97         GList *work;
98
99         spinner_set_timeout(sp, 0);
100
101         work = sp->list;
102         while (work)
103                 {
104                 GdkPixbuf *pb = work->data;
105                 work = work->next;
106
107                 g_object_unref(pb);
108                 }
109         g_list_free(sp->list);
110         g_free(sp);
111 }
112
113 GtkWidget *spinner_new(const gchar *path, gint interval)
114 {
115         SpinnerData *sp;
116
117         sp = g_new0(SpinnerData, 1);
118         sp->list = NULL;
119         sp->timer_id = -1;
120
121         if (path)
122                 {
123                 gchar *pathl;
124                 GdkPixbuf *pb;
125                 gint n;
126                 gchar *buf;
127
128                 pathl = path_from_utf8(path);
129
130                 n = 0;
131                 buf = g_strdup_printf("%s%02d.png", pathl, n);
132                 while ((pb = gdk_pixbuf_new_from_file(buf, NULL)))
133                         {
134                         sp->list = g_list_append(sp->list, pb);
135
136                         n++;
137                         g_free(buf);
138                         buf = g_strdup_printf("%s%02d.png", pathl, n);
139                         }
140                 g_free(buf);
141
142                 g_free(pathl);
143                 }
144
145         if (!sp->list)
146                 {
147                 GdkPixbuf *pb;
148                 gint n;
149                 gint w, h;
150
151                 pb = gdk_pixbuf_new_from_inline (-1, icon_spinner, FALSE, NULL);
152                 w = gdk_pixbuf_get_width(pb);
153                 h = gdk_pixbuf_get_height(pb) / SPINNER_FRAMES;
154                 for (n = 0; n < SPINNER_FRAMES; n++)
155                         {
156                         sp->list = g_list_append(sp->list,
157                                                  gdk_pixbuf_new_subpixbuf(pb, 0, n * h, w, h));
158                         }
159                 /* pb pixels is inline static, so the subpixbufs in sp->list will be ok */
160                 g_object_unref(pb);
161                 }
162
163         if (sp->list)
164                 {
165                 GdkPixbuf *pb;
166
167                 pb = sp->list->data;
168                 sp->image = gtk_image_new_from_pixbuf(pb);
169                 }
170         else
171                 {
172                 sp->image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
173                 }
174
175         g_object_set_data(G_OBJECT(sp->image), "spinner", sp);
176
177         g_signal_connect(G_OBJECT(sp->image), "destroy",
178                          G_CALLBACK(spinner_destroy_cb), sp);
179
180         spinner_set_timeout(sp, interval);
181
182         return sp->image;
183 }
184
185 void spinner_set_interval(GtkWidget *spinner, gint interval)
186 {
187         SpinnerData *sp;
188
189         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
190
191         spinner_set_timeout(sp, interval);
192 }
193
194 void spinner_step(GtkWidget *spinner, gint reset)
195 {
196         SpinnerData *sp;
197
198         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
199         if (sp->timer_id != -1)
200                 {
201                 printf("spinner warning: attempt to step with timer set\n");
202                 return;
203                 }
204
205         if (reset)
206                 {
207                 spinner_set_frame(sp, 0);
208                 }
209         else
210                 {
211                 spinner_increment_frame(sp);
212                 }
213 }