Wed Nov 29 14:28:30 2006 John Ellis <johne@verizon.net>
[geeqie.git] / src / image-overlay.c
1 /*
2  * GQview
3  * (C) 2006 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 #include "gqview.h"
13 #include "image-overlay.h"
14
15 #include "collect.h"
16 #include "filelist.h"
17 #include "image.h"
18 #include "img-view.h"
19 #include "layout.h"
20 #include "pixbuf-renderer.h"
21 #include "pixbuf_util.h"
22
23
24 /*
25  *----------------------------------------------------------------------------
26  * image overlay
27  *----------------------------------------------------------------------------
28  */
29
30 typedef struct _OverlayStateData OverlayStateData;
31 struct _OverlayStateData {
32         ImageWindow *imd;
33         ImageState changed_states;
34
35         gint show_info;
36         gint show_status;
37
38         gint ovl_info;
39         gint ovl_color;
40         gint ovl_rotate;
41         gint ovl_end;
42
43         gint idle_id;
44         gint timer_id;
45         gulong destroy_id;
46 };
47
48 #define OSD_DATA "overlay-data"
49
50 #define OSD_INFO_X 10
51 #define OSD_INFO_Y -10
52
53
54 static GdkPixbuf *image_osd_info_render(ImageWindow *imd)
55 {
56         GdkPixbuf *pixbuf;
57         gint width, height;
58         PangoLayout *layout;
59         const gchar *name;
60         gchar *name_escaped;
61         gchar *text;
62         gchar *size;
63         gint n, t;
64         CollectionData *cd;
65         CollectInfo *info;
66         gchar *ct;
67
68         name = image_get_name(imd);
69         if (name)
70                 {
71                 name_escaped = g_markup_escape_text(name, -1);
72                 }
73         else
74                 {
75                 name_escaped = NULL;
76                 }
77
78         cd = image_get_collection(imd, &info);
79         if (cd)
80                 {
81                 gchar *buf;
82
83                 t = g_list_length(cd->list);
84                 n = g_list_index(cd->list, info) + 1;
85                 buf = g_markup_escape_text((cd->name) ? cd->name : _("Untitled"), -1);
86                 ct = g_strdup_printf("<i>%s</i>\n", buf);
87                 g_free(buf);
88                 }
89         else
90                 {
91                 LayoutWindow *lw;
92
93                 lw = layout_find_by_image(imd);
94                 if (lw)
95                         {
96                         if (lw->slideshow)
97                                 {
98                                 n = g_list_length(lw->slideshow->list_done);
99                                 t = n + g_list_length(lw->slideshow->list);
100                                 }
101                         else
102                                 {
103                                 t = layout_list_count(lw, NULL);
104                                 n = layout_list_get_index(lw, image_get_path(lw->image)) + 1;
105                                 }
106                         }
107                 else if (view_window_find_image(imd, &n, &t))
108                         {
109                         n++;
110                         }
111                 else
112                         {
113                         t = 1;
114                         n = 1;
115                         }
116
117                 if (n < 1) n = 1;
118                 if (t < 1) t = 1;
119
120                 ct = g_strdup("");
121                 }
122
123         size = text_from_size_abrev(imd->size);
124         if (!name_escaped)
125                 {
126                 text = g_strdup_printf(_("Untitled"));
127                 }
128         else if (imd->unknown)
129                 {
130                 text = g_strdup_printf("%s(%d/%d) <b>%s</b>\n%s - %s", ct,
131                                        n, t, name_escaped,
132                                        text_from_time(imd->mtime), size);
133                 }
134         else
135                 {
136                 gint w, h;
137
138                 if (imd->delay_flip &&
139                     imd->il && imd->il->pixbuf &&
140                     image_get_pixbuf(imd) != imd->il->pixbuf)
141                         {
142                         w = gdk_pixbuf_get_width(imd->il->pixbuf);
143                         h = gdk_pixbuf_get_height(imd->il->pixbuf);
144                         }
145                 else
146                         {
147                         pixbuf_renderer_get_image_size(PIXBUF_RENDERER(imd->pr), &w, &h);
148                         }
149
150                 text = g_strdup_printf("%s(%d/%d) <b>%s</b>\n%d x %d - %s - %s", ct,
151                                        n, t, name_escaped,
152                                        w, h,
153                                        text_from_time(imd->mtime), size);
154                 }
155         g_free(size);
156         g_free(ct);
157         g_free(name_escaped);
158
159         layout = gtk_widget_create_pango_layout(imd->pr, NULL);
160         pango_layout_set_markup(layout, text, -1);
161         g_free(text);
162
163         pango_layout_get_pixel_size(layout, &width, &height);
164
165         width += 10;
166         height += 10;
167
168         pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
169         pixbuf_set_rect_fill(pixbuf, 3, 3, width-6, height-6, 240, 240, 240, 210);
170         pixbuf_set_rect(pixbuf, 0, 0, width, height, 240, 240, 240, 80, 1, 1, 1, 1);
171         pixbuf_set_rect(pixbuf, 1, 1, width-2, height-2, 240, 240, 240, 130, 1, 1, 1, 1);
172         pixbuf_set_rect(pixbuf, 2, 2, width-4, height-4, 240, 240, 240, 180, 1, 1, 1, 1);
173         pixbuf_pixel_set(pixbuf, 0, 0, 0, 0, 0, 0);
174         pixbuf_pixel_set(pixbuf, width - 1, 0, 0, 0, 0, 0);
175         pixbuf_pixel_set(pixbuf, 0, height - 1, 0, 0, 0, 0);
176         pixbuf_pixel_set(pixbuf, width - 1, height - 1, 0, 0, 0, 0);
177
178         pixbuf_draw_layout(pixbuf, layout, imd->pr, 5, 5, 0, 0, 0, 255);
179
180         g_object_unref(G_OBJECT(layout));
181
182         return pixbuf;
183 }
184
185 static void image_osd_ovl_reset(OverlayStateData *osd, gint *id)
186 {
187         if (*id)
188                 {
189                 image_overlay_remove(osd->imd, *id);
190                 *id = 0;
191                 }
192 }
193
194 static gint image_osd_update_cb(gpointer data)
195 {
196         OverlayStateData *osd = data;
197
198         if (osd->show_info)
199                 {
200                 if (osd->changed_states & IMAGE_STATE_IMAGE)
201                         {
202                         GdkPixbuf *pixbuf;
203
204                         pixbuf = image_osd_info_render(osd->imd);
205                         if (osd->ovl_info == 0)
206                                 {
207                                 osd->ovl_info = image_overlay_add(osd->imd, pixbuf,
208                                                                   OSD_INFO_X, OSD_INFO_Y, TRUE, FALSE);
209                                 }
210                         else
211                                 {
212                                 image_overlay_set(osd->imd, osd->ovl_info, pixbuf, OSD_INFO_X, OSD_INFO_Y);
213                                 }
214                         g_object_unref(pixbuf);
215                         }
216                 }
217         else
218                 {
219                 image_osd_ovl_reset(osd, & osd->ovl_info);
220                 }
221
222         if (osd->show_status)
223                 {
224                 }
225         else
226                 {
227                 image_osd_ovl_reset(osd, & osd->ovl_color);
228                 image_osd_ovl_reset(osd, & osd->ovl_rotate);
229                 image_osd_ovl_reset(osd, & osd->ovl_end);
230                 }
231
232         osd->idle_id = -1;
233         return FALSE;
234 }
235
236 static void image_osd_update_schedule(OverlayStateData *osd, gint force)
237 {
238         if (force) osd->changed_states |= IMAGE_STATE_IMAGE;
239
240         if (osd->idle_id == -1)
241                 {
242                 osd->idle_id = g_idle_add_full(G_PRIORITY_HIGH, image_osd_update_cb, osd, NULL);
243                 }
244 }
245
246 void image_osd_update(ImageWindow *imd)
247 {
248         OverlayStateData *osd;
249
250         if (!imd) return;
251
252         osd = g_object_get_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA");
253         if (!osd) return;
254
255         image_osd_update_schedule(osd, TRUE);
256 }
257
258 static void image_osd_state_cb(ImageWindow *imd, ImageState state, gpointer data)
259 {
260         OverlayStateData *osd = data;
261
262         osd->changed_states |= state;
263         image_osd_update_schedule(osd, FALSE);
264 }
265
266 static void image_osd_free(OverlayStateData *osd)
267 {
268         if (!osd) return;
269
270         if (osd->idle_id != -1) g_source_remove(osd->idle_id);
271
272         if (osd->imd)
273                 {
274                 g_object_set_data(G_OBJECT(osd->imd->pr), "IMAGE_OVERLAY_DATA", NULL);
275                 g_signal_handler_disconnect(osd->imd->pr, osd->destroy_id);
276
277                 image_set_state_func(osd->imd, NULL, NULL);
278                 image_overlay_remove(osd->imd, osd->ovl_info);
279                 }
280
281         g_free(osd);
282 }
283
284 static void image_osd_remove(ImageWindow *imd)
285 {
286         OverlayStateData *osd;
287
288         osd = g_object_get_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA");
289         image_osd_free(osd);
290 }
291
292 static void image_osd_destroy_cb(GtkWidget *widget, gpointer data)
293 {
294         OverlayStateData *osd = data;
295
296         osd->imd = NULL;
297         image_osd_free(osd);
298 }
299
300 static void image_osd_enable(ImageWindow *imd, gint info, gint status)
301 {
302         OverlayStateData *osd;
303
304         osd = g_object_get_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA");
305         if (!osd)
306                 {
307                 osd = g_new0(OverlayStateData, 1);
308                 osd->imd = imd;
309                 osd->idle_id = -1;
310                 osd->timer_id = -1;
311
312                 osd->destroy_id = g_signal_connect(G_OBJECT(imd->pr), "destroy",
313                                                    G_CALLBACK(image_osd_destroy_cb), osd);
314                 g_object_set_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA", osd);
315
316                 image_set_state_func(osd->imd, image_osd_state_cb, osd);
317                 }
318
319         if (osd->show_info != info ||
320             osd->show_status != status)
321                 {
322                 osd->show_info = info;
323                 osd->show_status = status;
324
325                 image_osd_update_schedule(osd, TRUE);
326                 }
327 }
328
329 void image_osd_set(ImageWindow *imd, gint info, gint status)
330 {
331         if (!imd) return;
332
333         if (!info && !status)
334                 {
335                 image_osd_remove(imd);
336                 return;
337                 }
338
339         image_osd_enable(imd, info, status);
340 }
341
342 gint image_osd_get(ImageWindow *imd, gint *info, gint *status)
343 {
344         OverlayStateData *osd;
345
346         if (!imd) return FALSE;
347
348         osd = g_object_get_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA");
349         if (!osd) return FALSE;
350
351         if (info) *info = osd->show_info;
352         if (status) *status = osd->show_status;
353
354         return TRUE;
355 }
356