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