Simplify vflist_get_formatted()
[geeqie.git] / src / ui_spinner.c
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include "config.h"
24 #endif
25 #include "intl.h"
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <gtk/gtk.h>
32
33 #include "main.h"
34 #include "ui_spinner.h"
35
36 #include "ui_icons.h"
37 #include "ui_fileops.h"
38
39
40 #define SPINNER_FRAMES 19
41
42
43 /*
44  *-----------------------------------------------------------------------------
45  * spinner utility
46  *-----------------------------------------------------------------------------
47  */
48
49 typedef struct _SpinnerData SpinnerData;
50 struct _SpinnerData {
51         GtkWidget *image;
52         GList *list;            /* list of pixbufs */
53         guint frame;
54         guint timer_id; /* event source id */
55 };
56
57 static void spinner_set_frame(SpinnerData *sp, guint frame)
58 {
59         GdkPixbuf *pb;
60
61         pb = g_list_nth_data(sp->list, frame);
62         if (pb) gtk_image_set_from_pixbuf(GTK_IMAGE(sp->image), pb);
63
64         sp->frame = frame;
65 }
66
67 static void spinner_increment_frame(SpinnerData *sp)
68 {
69         sp->frame++;
70         if (sp->frame >= g_list_length(sp->list)) sp->frame = 1;
71         spinner_set_frame(sp, sp->frame);
72 }
73
74 static gboolean spinner_loop_cb(gpointer data)
75 {
76         SpinnerData *sp = data;
77
78         if (sp->list) spinner_increment_frame(sp);
79
80         return TRUE;
81 }
82
83 static void spinner_set_timeout(SpinnerData *sp, gint interval)
84 {
85         if (!sp) return;
86
87         if (sp->timer_id)
88                 {
89                 g_source_remove(sp->timer_id);
90                 sp->timer_id = 0;
91                 }
92
93         if (interval > 0)
94                 {
95                 sp->timer_id = g_timeout_add(interval, spinner_loop_cb, sp);
96                 }
97         else if (interval < 0)
98                 {
99                 spinner_set_frame(sp, 0);
100                 }
101
102         gtk_widget_set_sensitive(sp->image, (interval >= 0));
103 }
104
105 static void spinner_destroy_cb(GtkWidget *widget, gpointer data)
106 {
107         SpinnerData *sp = data;
108         GList *work;
109
110         spinner_set_timeout(sp, 0);
111
112         work = sp->list;
113         while (work)
114                 {
115                 GdkPixbuf *pb = work->data;
116                 work = work->next;
117
118                 g_object_unref(pb);
119                 }
120         g_list_free(sp->list);
121         g_free(sp);
122 }
123
124 GtkWidget *spinner_new(const gchar *path, gint interval)
125 {
126         SpinnerData *sp;
127
128         sp = g_new0(SpinnerData, 1);
129
130         if (path)
131                 {
132                 gchar *pathl;
133                 GdkPixbuf *pb;
134                 gint n;
135                 gchar *buf;
136
137                 pathl = path_from_utf8(path);
138
139                 n = 0;
140                 buf = g_strdup_printf("%s%02d.png", pathl, n);
141                 while ((pb = gdk_pixbuf_new_from_file(buf, NULL)))
142                         {
143                         sp->list = g_list_append(sp->list, pb);
144
145                         n++;
146                         g_free(buf);
147                         buf = g_strdup_printf("%s%02d.png", pathl, n);
148                         }
149                 g_free(buf);
150
151                 g_free(pathl);
152                 }
153
154         if (!sp->list)
155                 {
156                 GdkPixbuf *pb;
157                 gint n;
158                 gint w, h;
159
160                 pb = gdk_pixbuf_new_from_inline(-1, icon_spinner, FALSE, NULL);
161                 w = gdk_pixbuf_get_width(pb);
162                 h = gdk_pixbuf_get_height(pb) / SPINNER_FRAMES;
163                 for (n = 0; n < SPINNER_FRAMES; n++)
164                         {
165                         sp->list = g_list_append(sp->list,
166                                                  gdk_pixbuf_new_subpixbuf(pb, 0, n * h, w, h));
167                         }
168                 /* pb pixels is inline static, so the subpixbufs in sp->list will be ok */
169                 g_object_unref(pb);
170                 }
171
172         if (sp->list)
173                 {
174                 GdkPixbuf *pb;
175
176                 pb = sp->list->data;
177                 sp->image = gtk_image_new_from_pixbuf(pb);
178                 }
179         else
180                 {
181                 sp->image = gtk_image_new_from_stock(GTK_STOCK_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
182                 }
183
184         g_object_set_data(G_OBJECT(sp->image), "spinner", sp);
185
186         g_signal_connect(G_OBJECT(sp->image), "destroy",
187                          G_CALLBACK(spinner_destroy_cb), sp);
188
189         spinner_set_timeout(sp, interval);
190
191         return sp->image;
192 }
193
194 void spinner_set_interval(GtkWidget *spinner, gint interval)
195 {
196         SpinnerData *sp;
197
198         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
199
200         spinner_set_timeout(sp, interval);
201 }
202
203 void spinner_step(GtkWidget *spinner, gboolean reset)
204 {
205         SpinnerData *sp;
206
207         sp = g_object_get_data(G_OBJECT(spinner), "spinner");
208         if (sp->timer_id)
209                 {
210                 log_printf("spinner warning: attempt to step with timer set\n");
211                 return;
212                 }
213
214         if (reset)
215                 {
216                 spinner_set_frame(sp, 0);
217                 }
218         else
219                 {
220                 spinner_increment_frame(sp);
221                 }
222 }
223 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */