9307529c4f2ffd83b576269333da454499466a68
[geeqie.git] / src / ui-spinner.cc
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 #include "main.h"
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 struct SpinnerData {
39         GtkWidget *image;
40         GList *list;            /* list of pixbufs */
41         guint frame;
42         guint timer_id; /* event source id */
43 };
44
45 static void spinner_set_frame(SpinnerData *sp, guint frame)
46 {
47         GdkPixbuf *pb;
48
49         pb = static_cast<GdkPixbuf *>(g_list_nth_data(sp->list, frame));
50         if (pb) gtk_image_set_from_pixbuf(GTK_IMAGE(sp->image), pb);
51
52         sp->frame = frame;
53 }
54
55 static void spinner_increment_frame(SpinnerData *sp)
56 {
57         sp->frame++;
58         if (sp->frame >= g_list_length(sp->list)) sp->frame = 1;
59         spinner_set_frame(sp, sp->frame);
60 }
61
62 static gboolean spinner_loop_cb(gpointer data)
63 {
64         auto sp = static_cast<SpinnerData *>(data);
65
66         if (sp->list) spinner_increment_frame(sp);
67
68         return TRUE;
69 }
70
71 static void spinner_set_timeout(SpinnerData *sp, gint interval)
72 {
73         if (!sp) return;
74
75         if (sp->timer_id)
76                 {
77                 g_source_remove(sp->timer_id);
78                 sp->timer_id = 0;
79                 }
80
81         if (interval > 0)
82                 {
83                 sp->timer_id = g_timeout_add(interval, spinner_loop_cb, sp);
84                 }
85         else if (interval < 0)
86                 {
87                 spinner_set_frame(sp, 0);
88                 }
89
90         gtk_widget_set_sensitive(sp->image, (interval >= 0));
91 }
92
93 static void spinner_destroy_cb(GtkWidget *, gpointer data)
94 {
95         auto sp = static_cast<SpinnerData *>(data);
96
97         spinner_set_timeout(sp, 0);
98
99         g_list_free_full(sp->list, g_object_unref);
100         g_free(sp);
101 }
102
103 GtkWidget *spinner_new(const gchar *path, gint interval)
104 {
105         SpinnerData *sp;
106
107         sp = g_new0(SpinnerData, 1);
108
109         if (path)
110                 {
111                 gchar *pathl;
112                 GdkPixbuf *pb;
113                 gint n;
114                 gchar *buf;
115
116                 pathl = path_from_utf8(path);
117
118                 n = 0;
119                 buf = g_strdup_printf("%s%02d.png", pathl, n);
120                 while ((pb = gdk_pixbuf_new_from_file(buf, nullptr)))
121                         {
122                         sp->list = g_list_append(sp->list, pb);
123
124                         n++;
125                         g_free(buf);
126                         buf = g_strdup_printf("%s%02d.png", pathl, n);
127                         }
128                 g_free(buf);
129
130                 g_free(pathl);
131                 }
132
133         if (!sp->list)
134                 {
135                 GdkPixbuf *pb;
136                 gint n;
137                 gint w, h;
138
139                 pb = gdk_pixbuf_new_from_inline(-1, icon_spinner, FALSE, nullptr);
140                 w = gdk_pixbuf_get_width(pb);
141                 h = gdk_pixbuf_get_height(pb) / SPINNER_FRAMES;
142                 for (n = 0; n < SPINNER_FRAMES; n++)
143                         {
144                         sp->list = g_list_append(sp->list,
145                                                  gdk_pixbuf_new_subpixbuf(pb, 0, n * h, w, h));
146                         }
147                 /* pb pixels is inline static, so the subpixbufs in sp->list will be ok */
148                 g_object_unref(pb);
149                 }
150
151         if (sp->list)
152                 {
153                 GdkPixbuf *pb;
154
155                 pb = static_cast<GdkPixbuf *>(sp->list->data);
156                 sp->image = gtk_image_new_from_pixbuf(pb);
157                 }
158         else
159                 {
160                 sp->image = gtk_image_new_from_icon_name(GQ_ICON_MISSING_IMAGE, GTK_ICON_SIZE_DIALOG);
161                 }
162
163         g_object_set_data(G_OBJECT(sp->image), "spinner", sp);
164
165         g_signal_connect(G_OBJECT(sp->image), "destroy",
166                          G_CALLBACK(spinner_destroy_cb), sp);
167
168         spinner_set_timeout(sp, interval);
169
170         return sp->image;
171 }
172
173 void spinner_set_interval(GtkWidget *spinner, gint interval)
174 {
175         SpinnerData *sp;
176
177         sp = static_cast<SpinnerData *>(g_object_get_data(G_OBJECT(spinner), "spinner"));
178
179         spinner_set_timeout(sp, interval);
180 }
181
182 #pragma GCC diagnostic push
183 #pragma GCC diagnostic ignored "-Wunused-function"
184 void spinner_step_unused(GtkWidget *spinner, gboolean reset)
185 {
186         SpinnerData *sp;
187
188         sp = static_cast<SpinnerData *>(g_object_get_data(G_OBJECT(spinner), "spinner"));
189         if (sp->timer_id)
190                 {
191                 log_printf("spinner warning: attempt to step with timer set\n");
192                 return;
193                 }
194
195         if (reset)
196                 {
197                 spinner_set_frame(sp, 0);
198                 }
199         else
200                 {
201                 spinner_increment_frame(sp);
202                 }
203 }
204 #pragma GCC diagnostic pop
205 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */