Silence GTK deprecation warning in unused function
[geeqie.git] / src / image-overlay.cc
1 /*
2  * Copyright (C) 2006 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 "image-overlay.h"
23
24 #include <cstring>
25
26 #include <gdk-pixbuf/gdk-pixbuf.h>
27 #include <glib-object.h>
28 #include <gtk/gtk.h>
29 #include <pango/pango.h>
30
31 #include "collect.h"
32 #include "debug.h"
33 #include "filedata.h"
34 #include "histogram.h"
35 #include "image-load.h"
36 #include "image.h"
37 #include "img-view.h"
38 #include "intl.h"
39 #include "layout.h"
40 #include "main-defines.h"
41 #include "options.h"
42 #include "osd.h"
43 #include "pixbuf-renderer.h"
44 #include "pixbuf-util.h"
45 #include "slideshow.h"
46 #include "typedefs.h"
47 #include "ui-fileops.h"
48
49 namespace
50 {
51
52 constexpr gint IMAGE_OSD_DEFAULT_DURATION = 30;
53
54 } // namespace
55
56 struct HistMap;
57
58 /*
59  *----------------------------------------------------------------------------
60  * image overlay
61  *----------------------------------------------------------------------------
62  */
63
64
65 struct OverlayStateData {
66         ImageWindow *imd;
67         ImageState changed_states;
68         NotifyType notify;
69
70         Histogram *histogram;
71
72         OsdShowFlags show;
73         OverlayRendererFlags origin;
74
75         gint ovl_info;
76
77         gint x;
78         gint y;
79
80         gint icon_time[IMAGE_OSD_COUNT];
81         gint icon_id[IMAGE_OSD_COUNT];
82
83         guint idle_id; /* event source id */
84         guint timer_id; /* event source id */
85         gulong destroy_id;
86 };
87
88
89 struct OSDIcon {
90         gboolean reset; /* reset on new image */
91         gint x;         /* x, y offset */
92         gint y;
93         gchar *key;     /* inline pixbuf */
94 };
95
96 static OSDIcon osd_icons[] = {
97         {  TRUE,   0,   0, nullptr },                   /* none */
98         {  TRUE, -10, -10, nullptr },                   /* auto rotated */
99         {  TRUE, -10, -10, nullptr },                   /* user rotated */
100         {  TRUE, -40, -10, nullptr },                   /* color embedded */
101         {  TRUE, -70, -10, nullptr },                   /* first image */
102         {  TRUE, -70, -10, nullptr },                   /* last image */
103         { FALSE, -70, -10, nullptr },                   /* osd enabled */
104         { FALSE, 0, 0, nullptr }
105 };
106
107 #define OSD_DATA "overlay-data"
108
109 enum {
110         HISTOGRAM_HEIGHT = 140,
111         HISTOGRAM_WIDTH =  256
112 };
113
114 static void image_osd_timer_schedule(OverlayStateData *osd);
115
116 void set_image_overlay_template_string(gchar **template_string, const gchar *value)
117 {
118         g_assert(template_string);
119
120         g_free(*template_string);
121         *template_string = g_strdup(value);
122 }
123
124
125 void set_default_image_overlay_template_string(gchar **template_string)
126 {
127         set_image_overlay_template_string(template_string, DEFAULT_OVERLAY_INFO);
128 }
129
130 void set_image_overlay_font_string(gchar **font_string, const gchar *value)
131 {
132         g_assert(font_string);
133
134         g_free(*font_string);
135         *font_string = g_strdup(value);
136 }
137
138 static OverlayStateData *image_get_osd_data(ImageWindow *imd)
139 {
140         OverlayStateData *osd;
141
142         if (!imd) return nullptr;
143
144         g_assert(imd->pr);
145
146         osd = static_cast<OverlayStateData *>(g_object_get_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA"));
147         return osd;
148 }
149
150 static void image_set_osd_data(ImageWindow *imd, OverlayStateData *osd)
151 {
152         g_assert(imd);
153         g_assert(imd->pr);
154         g_object_set_data(G_OBJECT(imd->pr), "IMAGE_OVERLAY_DATA", osd);
155 }
156
157 /*
158  *----------------------------------------------------------------------------
159  * image histogram
160  *----------------------------------------------------------------------------
161  */
162
163
164 void image_osd_histogram_toggle_channel(ImageWindow *imd)
165 {
166         OverlayStateData *osd = image_get_osd_data(imd);
167
168         if (!osd || !osd->histogram) return;
169
170         histogram_toggle_channel(osd->histogram);
171         image_osd_update(imd);
172 }
173
174 void image_osd_histogram_toggle_mode(ImageWindow *imd)
175 {
176         OverlayStateData *osd = image_get_osd_data(imd);
177
178         if (!osd || !osd->histogram) return;
179
180         histogram_toggle_mode(osd->histogram);
181         image_osd_update(imd);
182 }
183
184 void image_osd_histogram_set_channel(ImageWindow *imd, gint chan)
185 {
186         OverlayStateData *osd = image_get_osd_data(imd);
187
188         if (!osd || !osd->histogram) return;
189
190         histogram_set_channel(osd->histogram, chan);
191         image_osd_update(imd);
192 }
193
194 void image_osd_histogram_set_mode(ImageWindow *imd, gint mode)
195 {
196         OverlayStateData *osd = image_get_osd_data(imd);
197
198         if (!osd || !osd->histogram) return;
199
200         histogram_set_mode(osd->histogram, mode);
201         image_osd_update(imd);
202 }
203
204 gint image_osd_histogram_get_channel(ImageWindow *imd)
205 {
206         OverlayStateData *osd = image_get_osd_data(imd);
207
208         if (!osd || !osd->histogram) return HCHAN_DEFAULT;
209
210         return histogram_get_channel(osd->histogram);
211 }
212
213 gint image_osd_histogram_get_mode(ImageWindow *imd)
214 {
215         OverlayStateData *osd = image_get_osd_data(imd);
216
217         if (!osd || !osd->histogram) return 0;
218
219         return histogram_get_mode(osd->histogram);
220 }
221
222 void image_osd_toggle(ImageWindow *imd)
223 {
224         OsdShowFlags show;
225         if (!imd) return;
226
227         show = image_osd_get(imd);
228         if (show == OSD_SHOW_NOTHING)
229                 {
230                 image_osd_set(imd, static_cast<OsdShowFlags>(OSD_SHOW_INFO | OSD_SHOW_STATUS));
231                 return;
232                 }
233
234         if (show & OSD_SHOW_HISTOGRAM)
235                 {
236                 image_osd_set(imd, OSD_SHOW_NOTHING);
237                 }
238         else
239                 {
240                 image_osd_set(imd, static_cast<OsdShowFlags>(show | OSD_SHOW_HISTOGRAM));
241                 }
242 }
243
244 static GdkPixbuf *image_osd_info_render(OverlayStateData *osd)
245 {
246         GdkPixbuf *pixbuf = nullptr;
247         gint width;
248         gint height;
249         PangoLayout *layout;
250         const gchar *name;
251         gchar *text;
252         gboolean with_hist;
253         const HistMap *histmap = nullptr;
254         ImageWindow *imd = osd->imd;
255         FileData *fd = image_get_fd(imd);
256         PangoFontDescription *font_desc;
257
258         if (!fd) return nullptr;
259
260         name = image_get_name(imd);
261         if (name)
262                 {
263                 gint n;
264                 gint t;
265                 CollectionData *cd;
266                 CollectInfo *info;
267                 GHashTable *vars;
268
269                 vars = g_hash_table_new_full(g_str_hash, g_str_equal, nullptr, g_free);
270
271                 cd = image_get_collection(imd, &info);
272                 if (cd)
273                         {
274                         t = g_list_length(cd->list);
275                         n = g_list_index(cd->list, info) + 1;
276                         if (cd->name)
277                                 {
278                                 if (file_extension_match(cd->name, GQ_COLLECTION_EXT))
279                                         osd_template_insert(vars, "collection", remove_extension_from_path(cd->name), OSDT_FREE);
280                                 else
281                                         osd_template_insert(vars, "collection", cd->name, OSDT_NONE);
282                                 }
283                         else
284                                 {
285                                 osd_template_insert(vars, "collection", _("Untitled"), OSDT_NONE);
286                                 }
287                         }
288                 else
289                         {
290                         LayoutWindow *lw = layout_find_by_image(imd);
291                         if (lw)
292                                 {
293                                 if (lw->slideshow)
294                                         {
295                                         n = g_list_length(lw->slideshow->list_done);
296                                         t = n + g_list_length(lw->slideshow->list);
297                                         if (n == 0) n = t;
298                                         }
299                                 else
300                                         {
301                                         t = layout_list_count(lw, nullptr);
302                                         n = layout_list_get_index(lw, image_get_fd(lw->image)) + 1;
303                                         }
304                                 }
305                         else if (view_window_find_image(imd, &n, &t))
306                                 {
307                                 n++;
308                                 }
309                         else
310                                 {
311                                 t = 1;
312                                 n = 1;
313                                 }
314
315                         if (n < 1) n = 1;
316                         if (t < 1) t = 1;
317
318                         osd_template_insert(vars, "collection", nullptr, OSDT_NONE);
319                         }
320
321                 osd_template_insert(vars, "number", g_strdup_printf("%d", n), OSDT_NO_DUP);
322                 osd_template_insert(vars, "total", g_strdup_printf("%d", t), OSDT_NO_DUP);
323                 osd_template_insert(vars, "name", const_cast<gchar *>(name), OSDT_NONE);
324                 osd_template_insert(vars, "path", const_cast<gchar *>(image_get_path(imd)), OSDT_NONE);
325                 osd_template_insert(vars, "date", imd->image_fd ? (const_cast<gchar *>(text_from_time(imd->image_fd->date))) : "", OSDT_NONE);
326                 osd_template_insert(vars, "size", imd->image_fd ? (text_from_size_abrev(imd->image_fd->size)) : g_strdup(""), OSDT_FREE);
327                 osd_template_insert(vars, "zoom", image_zoom_get_as_text(imd), OSDT_FREE);
328
329                 if (!imd->unknown)
330                         {
331                         gint w;
332                         gint h;
333                         GdkPixbuf *load_pixbuf = image_loader_get_pixbuf(imd->il);
334
335                         if (imd->delay_flip &&
336                             imd->il && load_pixbuf &&
337                             image_get_pixbuf(imd) != load_pixbuf)
338                                 {
339                                 w = gdk_pixbuf_get_width(load_pixbuf);
340                                 h = gdk_pixbuf_get_height(load_pixbuf);
341                                 }
342                         else
343                                 {
344                                 image_get_image_size(imd, &w, &h);
345                                 }
346
347
348                         osd_template_insert(vars, "width", g_strdup_printf("%d", w), OSDT_NO_DUP);
349                         osd_template_insert(vars, "height", g_strdup_printf("%d", h), OSDT_NO_DUP);
350                         osd_template_insert(vars, "res", g_strdup_printf("%d Ã— %d", w, h), OSDT_FREE);
351                         }
352                 else
353                         {
354                         osd_template_insert(vars, "width", nullptr, OSDT_NONE);
355                         osd_template_insert(vars, "height", nullptr, OSDT_NONE);
356                         osd_template_insert(vars, "res", nullptr, OSDT_NONE);
357                         }
358
359                 text = image_osd_mkinfo(options->image_overlay.template_string, imd->image_fd, vars);
360                 g_hash_table_destroy(vars);
361
362         } else {
363                 /* When does this occur ?? */
364                 text = g_markup_escape_text(_("Untitled"), -1);
365         }
366
367         with_hist = ((osd->show & OSD_SHOW_HISTOGRAM) && osd->histogram);
368         if (with_hist)
369                 {
370                 histmap = histmap_get(imd->image_fd);
371                 if (!histmap)
372                         {
373                         histmap_start_idle(imd->image_fd);
374                         with_hist = FALSE;
375                         }
376                 }
377
378
379         {
380                 gint active_marks = 0;
381                 gint mark;
382                 gchar *text2;
383
384                 for (mark = 0; mark < FILEDATA_MARKS_SIZE; mark++)
385                         {
386                         active_marks += file_data_get_mark(fd, mark);
387                         }
388
389                 if (active_marks > 0)
390                         {
391                         GString *buf = g_string_sized_new(strlen(text) + 1 + FILEDATA_MARKS_SIZE * 2);
392
393                         if (*text)
394                                 {
395                                 g_string_append_printf(buf, "%s\n", text);
396                                 }
397
398                         for (mark = 0; mark < FILEDATA_MARKS_SIZE; mark++)
399                                 {
400                                 g_string_append_printf(buf, file_data_get_mark(fd, mark) ? " <span background='#FF00FF'>%c</span>" : " %c", '1' + (mark < 9 ? mark : -1) );
401                                 }
402
403                         g_free(text);
404                         text = g_string_free(buf, FALSE);
405                         }
406
407                 if (with_hist)
408                         {
409                         gchar *escaped_histogram_label = g_markup_escape_text(histogram_label(osd->histogram), -1);
410                         if (*text)
411                                 text2 = g_strdup_printf("%s\n%s", text, escaped_histogram_label);
412                         else
413                                 text2 = g_strdup(escaped_histogram_label);
414                         g_free(escaped_histogram_label);
415                         g_free(text);
416                         text = text2;
417                         }
418         }
419
420         font_desc = pango_font_description_from_string(options->image_overlay.font);
421         layout = gtk_widget_create_pango_layout(imd->pr, nullptr);
422         pango_layout_set_font_description(layout, font_desc);
423
424         pango_layout_set_markup(layout, text, -1);
425         g_free(text);
426
427         pango_layout_get_pixel_size(layout, &width, &height);
428         /* with empty text width is set to 0, but not height) */
429         if (width == 0)
430                 height = 0;
431         else if (height == 0)
432                 width = 0;
433         if (width > 0) width += 10;
434         if (height > 0) height += 10;
435
436         if (with_hist)
437                 {
438                 if (width < HISTOGRAM_WIDTH + 10) width = HISTOGRAM_WIDTH + 10;
439                 height += HISTOGRAM_HEIGHT + 5;
440                 }
441
442         if (width > 0 && height > 0)
443                 {
444                 pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, width, height);
445                 pixbuf_set_rect_fill(pixbuf, 3, 3, width-6, height-6, options->image_overlay.background_red, options->image_overlay.background_green,
446                                                                                                                         options->image_overlay.background_blue, options->image_overlay.background_alpha);
447                 pixbuf_set_rect(pixbuf, 0, 0, width, height, 240, 240, 240, 80, 1, 1, 1, 1);
448                 pixbuf_set_rect(pixbuf, 1, 1, width-2, height-2, 240, 240, 240, 130, 1, 1, 1, 1);
449                 pixbuf_set_rect(pixbuf, 2, 2, width-4, height-4, 240, 240, 240, 180, 1, 1, 1, 1);
450                 pixbuf_pixel_set(pixbuf, 0, 0, 0, 0, 0, 0);
451                 pixbuf_pixel_set(pixbuf, width - 1, 0, 0, 0, 0, 0);
452                 pixbuf_pixel_set(pixbuf, 0, height - 1, 0, 0, 0, 0);
453                 pixbuf_pixel_set(pixbuf, width - 1, height - 1, 0, 0, 0, 0);
454
455                 if (with_hist)
456                         {
457                         gint x = 5;
458                         gint y = height - HISTOGRAM_HEIGHT - 5;
459                         gint w = width - 10;
460
461                         pixbuf_set_rect_fill(pixbuf, x, y, w, HISTOGRAM_HEIGHT, 220, 220, 220, 210);
462                         histogram_draw(osd->histogram, histmap, pixbuf, x, y, w, HISTOGRAM_HEIGHT);
463                         }
464                 pixbuf_draw_layout(pixbuf, layout, imd->pr, 5, 5, options->image_overlay.text_red, options->image_overlay.text_green,
465                                                                                                                         options->image_overlay.text_blue, options->image_overlay.text_alpha);
466         }
467
468         g_object_unref(G_OBJECT(layout));
469
470         return pixbuf;
471 }
472
473 /**
474  * @brief Create non-standard icons for the OSD
475  * @param flag
476  * @returns
477  *
478  * IMAGE_OSD_COLOR
479  * \image html image-osd-color.png
480  * IMAGE_OSD_FIRST
481  * \image html image-osd-first.png
482  * IMAGE_OSD_ICON
483  * \image html image-osd-icon.png
484  * IMAGE_OSD_LAST
485  * \image html image-osd-last.png
486  * IMAGE_OSD_ROTATE_AUTO
487  * \image html image-osd-rotate-auto.png
488  *
489  */
490 static GdkPixbuf *image_osd_icon_pixbuf(ImageOSDFlag flag)
491 {
492         static GdkPixbuf **icons = nullptr;
493         GdkPixbuf *icon = nullptr;
494
495         if (!icons) icons = g_new0(GdkPixbuf *, IMAGE_OSD_COUNT);
496         if (icons[flag]) return icons[flag];
497
498         if (osd_icons[flag].key)
499                 {
500                 icon = pixbuf_inline(osd_icons[flag].key);
501                 }
502
503         if (!icon)
504                 {
505                 icon = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 24, 24);
506                 pixbuf_set_rect_fill(icon, 1, 1, 22, 22, 255, 255, 255, 200);
507                 pixbuf_set_rect(icon, 0, 0, 24, 24, 0, 0, 0, 128, 1, 1, 1, 1);
508                 switch (flag)
509                         {
510                         case IMAGE_OSD_ROTATE_AUTO:
511                                 pixbuf_set_rect(icon, 3, 8, 11, 12,
512                                                 0, 0, 0, 255,
513                                                 3, 0, 3, 0);
514                                 pixbuf_draw_triangle(icon, 14, 3, 6, 12,
515                                                      20, 9, 14, 15, 14, 3,
516                                                      0, 0, 0, 255);
517                                 break;
518                         case IMAGE_OSD_ROTATE_USER:
519                                 break;
520                         case IMAGE_OSD_COLOR:
521                                 pixbuf_set_rect_fill(icon, 3, 3, 18, 6, 200, 0, 0, 255);
522                                 pixbuf_set_rect_fill(icon, 3, 9, 18, 6, 0, 200, 0, 255);
523                                 pixbuf_set_rect_fill(icon, 3, 15, 18, 6, 0, 0, 200, 255);
524                                 break;
525                         case IMAGE_OSD_FIRST:
526                                 pixbuf_set_rect(icon, 3, 3, 18, 18, 0, 0, 0, 200, 3, 3, 3, 0);
527                                 pixbuf_draw_triangle(icon, 6, 5, 12, 6,
528                                                      12, 5, 18, 11, 6, 11,
529                                                      0, 0, 0, 255);
530                                 break;
531                         case IMAGE_OSD_LAST:
532                                 pixbuf_set_rect(icon, 3, 3, 18, 18, 0, 0, 0, 200, 3, 3, 0, 3);
533                                 pixbuf_draw_triangle(icon, 6, 12, 12, 6,
534                                                      12, 18, 6, 12, 18, 12,
535                                                      0, 0, 0, 255);
536                                 break;
537                         case IMAGE_OSD_ICON:
538                                 pixbuf_set_rect_fill(icon, 11, 3, 3, 12, 0, 0, 0, 255);
539                                 pixbuf_set_rect_fill(icon, 11, 17, 3, 3, 0, 0, 0, 255);
540                                 break;
541                         default:
542                                 break;
543                         }
544                 }
545
546         icons[flag] = icon;
547
548         return icon;
549 }
550
551 static gint image_overlay_add(ImageWindow *imd, GdkPixbuf *pixbuf, gint x, gint y,
552                               OverlayRendererFlags flags)
553 {
554         return pixbuf_renderer_overlay_add(reinterpret_cast<PixbufRenderer *>(imd->pr), pixbuf, x, y, flags);
555 }
556
557 static void image_overlay_set(ImageWindow *imd, gint id, GdkPixbuf *pixbuf, gint x, gint y)
558 {
559         pixbuf_renderer_overlay_set(reinterpret_cast<PixbufRenderer *>(imd->pr), id, pixbuf, x, y);
560 }
561
562 static void image_overlay_remove(ImageWindow *imd, gint id)
563 {
564         pixbuf_renderer_overlay_remove(reinterpret_cast<PixbufRenderer *>(imd->pr), id);
565 }
566
567 static void image_osd_icon_show(OverlayStateData *osd, ImageOSDFlag flag)
568 {
569         GdkPixbuf *pixbuf;
570
571         if (osd->icon_id[flag]) return;
572
573         pixbuf = image_osd_icon_pixbuf(flag);
574         if (!pixbuf) return;
575
576         osd->icon_id[flag] = image_overlay_add(osd->imd, pixbuf,
577                                                osd_icons[flag].x, osd_icons[flag].y,
578                                                OVL_RELATIVE);
579 }
580
581 static void image_osd_icon_hide(OverlayStateData *osd, ImageOSDFlag flag)
582 {
583         if (osd->icon_id[flag])
584                 {
585                 image_overlay_remove(osd->imd, osd->icon_id[flag]);
586                 osd->icon_id[flag] = 0;
587                 }
588 }
589
590 static void image_osd_icons_reset_time(OverlayStateData *osd)
591 {
592         gint i;
593
594         for (i = 0; i < IMAGE_OSD_COUNT; i++)
595                 {
596                 if (osd_icons[i].reset)
597                         {
598                         osd->icon_time[i] = 0;
599                         }
600                 }
601 }
602
603 static void image_osd_icons_update(OverlayStateData *osd)
604 {
605         gint i;
606
607         for (i = 0; i < IMAGE_OSD_COUNT; i++)
608                 {
609                 if (osd->icon_time[i] > 0)
610                         {
611                         image_osd_icon_show(osd, static_cast<ImageOSDFlag>(i));
612                         }
613                 else
614                         {
615                         image_osd_icon_hide(osd, static_cast<ImageOSDFlag>(i));
616                         }
617                 }
618 }
619
620 static void image_osd_icons_hide(OverlayStateData *osd)
621 {
622         gint i;
623
624         for (i = 0; i < IMAGE_OSD_COUNT; i++)
625                 {
626                 image_osd_icon_hide(osd, static_cast<ImageOSDFlag>(i));
627                 }
628 }
629
630 static void image_osd_info_show(OverlayStateData *osd, GdkPixbuf *pixbuf)
631 {
632         if (osd->ovl_info == 0)
633                 {
634                 osd->ovl_info = image_overlay_add(osd->imd, pixbuf, osd->x, osd->y, osd->origin);
635                 }
636         else
637                 {
638                 image_overlay_set(osd->imd, osd->ovl_info, pixbuf, osd->x, osd->y);
639                 }
640 }
641
642 static void image_osd_info_hide(OverlayStateData *osd)
643 {
644         if (osd->ovl_info == 0) return;
645
646         image_overlay_remove(osd->imd, osd->ovl_info);
647         osd->ovl_info = 0;
648 }
649
650 static gboolean image_osd_update_cb(gpointer data)
651 {
652         auto osd = static_cast<OverlayStateData *>(data);
653
654         if (osd->show & OSD_SHOW_INFO)
655                 {
656                 /* redraw when the image was changed,
657                    with histogram we have to redraw also when loading is finished */
658                 if (osd->changed_states & IMAGE_STATE_IMAGE ||
659                     (osd->changed_states & IMAGE_STATE_LOADING && osd->show & OSD_SHOW_HISTOGRAM) ||
660                     osd->notify & NOTIFY_HISTMAP)
661                         {
662                         GdkPixbuf *pixbuf;
663
664                         pixbuf = image_osd_info_render(osd);
665                         if (pixbuf)
666                                 {
667                                 image_osd_info_show(osd, pixbuf);
668                                 g_object_unref(pixbuf);
669                                 }
670                         else
671                                 {
672                                 image_osd_info_hide(osd);
673                                 }
674                         }
675                 }
676         else
677                 {
678                 image_osd_info_hide(osd);
679                 }
680
681         if (osd->show & OSD_SHOW_STATUS)
682                 {
683                 if (osd->changed_states & IMAGE_STATE_IMAGE)
684                         image_osd_icons_reset_time(osd);
685
686                 if (osd->changed_states & IMAGE_STATE_COLOR_ADJ)
687                         {
688                         osd->icon_time[IMAGE_OSD_COLOR] = IMAGE_OSD_DEFAULT_DURATION + 1;
689                         image_osd_timer_schedule(osd);
690                         }
691
692                 if (osd->changed_states & IMAGE_STATE_ROTATE_AUTO)
693                         {
694                         gint n = 0;
695
696                         if (osd->imd->state & IMAGE_STATE_ROTATE_AUTO)
697                                 {
698                                 n = 1;
699                                 if (!osd->imd->cm) n += IMAGE_OSD_DEFAULT_DURATION;
700                                 }
701
702                         osd->icon_time[IMAGE_OSD_ROTATE_AUTO] = n;
703                         image_osd_timer_schedule(osd);
704                         }
705
706                 image_osd_icons_update(osd);
707                 }
708         else
709                 {
710                 image_osd_icons_hide(osd);
711                 }
712
713         osd->changed_states = IMAGE_STATE_NONE;
714         osd->notify = static_cast<NotifyType>(0);
715         osd->idle_id = 0;
716         return G_SOURCE_REMOVE;
717 }
718
719 static void image_osd_update_schedule(OverlayStateData *osd, gboolean force)
720 {
721         if (force) osd->changed_states = static_cast<ImageState>(osd->changed_states | IMAGE_STATE_IMAGE);
722
723         if (!osd->idle_id)
724                 {
725                 osd->idle_id = g_idle_add_full(G_PRIORITY_HIGH, image_osd_update_cb, osd, nullptr);
726                 }
727 }
728
729 void image_osd_update(ImageWindow *imd)
730 {
731         OverlayStateData *osd = image_get_osd_data(imd);
732
733         if (!osd) return;
734
735         image_osd_update_schedule(osd, TRUE);
736 }
737
738 static gboolean image_osd_timer_cb(gpointer data)
739 {
740         auto osd = static_cast<OverlayStateData *>(data);
741         gboolean done = TRUE;
742         gboolean changed = FALSE;
743         gint i;
744
745         for (i = 0; i < IMAGE_OSD_COUNT; i++)
746                 {
747                 if (osd->icon_time[i] > 1)
748                         {
749                         osd->icon_time[i]--;
750                         if (osd->icon_time[i] < 2)
751                                 {
752                                 osd->icon_time[i] = 0;
753                                 changed = TRUE;
754                                 }
755                         else
756                                 {
757                                 done = FALSE;
758                                 }
759                         }
760                 }
761
762         if (changed) image_osd_update_schedule(osd, FALSE);
763
764         if (done)
765                 {
766                 osd->timer_id = 0;
767                 return FALSE;
768                 }
769
770         return TRUE;
771 }
772
773 static void image_osd_timer_schedule(OverlayStateData *osd)
774 {
775         if (!osd->timer_id)
776                 {
777                 osd->timer_id = g_timeout_add(100, image_osd_timer_cb, osd);
778                 }
779 }
780
781 static void image_osd_state_cb(ImageWindow *, ImageState state, gpointer data)
782 {
783         auto osd = static_cast<OverlayStateData *>(data);
784
785         osd->changed_states = static_cast<ImageState>(osd->changed_states | state);
786         image_osd_update_schedule(osd, FALSE);
787 }
788
789 static void image_osd_notify_cb(FileData *fd, NotifyType type, gpointer data)
790 {
791         auto osd = static_cast<OverlayStateData *>(data);
792
793         if ((type & (NOTIFY_HISTMAP)) && osd->imd && fd == osd->imd->image_fd)
794                 {
795                 DEBUG_1("Notify osd: %s %04x", fd->path, type);
796                 osd->notify = static_cast<NotifyType>(osd->notify | type);
797                 image_osd_update_schedule(osd, FALSE);
798                 }
799 }
800
801
802 static void image_osd_free(OverlayStateData *osd)
803 {
804         if (!osd) return;
805
806         if (osd->idle_id) g_source_remove(osd->idle_id);
807         if (osd->timer_id) g_source_remove(osd->timer_id);
808
809         file_data_unregister_notify_func(image_osd_notify_cb, osd);
810
811         if (osd->imd)
812                 {
813                 image_set_osd_data(osd->imd, nullptr);
814                 g_signal_handler_disconnect(osd->imd->pr, osd->destroy_id);
815
816                 image_set_state_func(osd->imd, nullptr, nullptr);
817
818                 image_osd_info_hide(osd);
819                 image_osd_icons_hide(osd);
820                 }
821
822         if (osd->histogram) histogram_free(osd->histogram);
823
824         g_free(osd);
825 }
826
827 static void image_osd_destroy_cb(GtkWidget *, gpointer data)
828 {
829         auto osd = static_cast<OverlayStateData *>(data);
830
831         osd->imd = nullptr;
832         image_osd_free(osd);
833 }
834
835 static void image_osd_enable(ImageWindow *imd, OsdShowFlags show)
836 {
837         OverlayStateData *osd = image_get_osd_data(imd);
838
839         if (!osd)
840                 {
841                 osd = g_new0(OverlayStateData, 1);
842                 osd->imd = imd;
843                 osd->show = OSD_SHOW_NOTHING;
844                 osd->x = options->image_overlay.x;
845                 osd->y = options->image_overlay.y;
846                 osd->origin = OVL_RELATIVE;
847
848                 osd->histogram = histogram_new();
849
850                 osd->destroy_id = g_signal_connect(G_OBJECT(imd->pr), "destroy",
851                                                    G_CALLBACK(image_osd_destroy_cb), osd);
852                 image_set_osd_data(imd, osd);
853
854                 image_set_state_func(osd->imd, image_osd_state_cb, osd);
855                 file_data_register_notify_func(image_osd_notify_cb, osd, NOTIFY_PRIORITY_LOW);
856                 }
857
858         if (show & OSD_SHOW_STATUS)
859                 image_osd_icon(imd, IMAGE_OSD_ICON, -1);
860
861         if (show != osd->show)
862                 image_osd_update_schedule(osd, TRUE);
863
864         osd->show = show;
865 }
866
867 void image_osd_set(ImageWindow *imd, OsdShowFlags show)
868 {
869         if (!imd) return;
870
871         image_osd_enable(imd, show);
872 }
873
874 OsdShowFlags image_osd_get(ImageWindow *imd)
875 {
876         OverlayStateData *osd = image_get_osd_data(imd);
877
878         return osd ? osd->show : OSD_SHOW_NOTHING;
879 }
880
881 Histogram *image_osd_get_histogram(ImageWindow *imd)
882 {
883         OverlayStateData *osd = image_get_osd_data(imd);
884
885         return osd ? osd->histogram : nullptr;
886 }
887
888 void image_osd_copy_status(ImageWindow *src, ImageWindow *dest)
889 {
890         Histogram *h_src;
891         Histogram *h_dest;
892         image_osd_set(dest, image_osd_get(src));
893
894         h_src = image_osd_get_histogram(src);
895         h_dest = image_osd_get_histogram(dest);
896
897         h_dest->histogram_mode = h_src->histogram_mode;
898         h_dest->histogram_channel = h_src->histogram_channel;
899
900 }
901
902 /* duration:
903     0 = hide
904     1 = show
905    2+ = show for duration tenths of a second
906    -1 = use default duration
907  */
908 void image_osd_icon(ImageWindow *imd, ImageOSDFlag flag, gint duration)
909 {
910         OverlayStateData *osd = image_get_osd_data(imd);
911
912         if (!osd) return;
913
914         if (flag >= IMAGE_OSD_COUNT) return;
915         if (duration < 0) duration = IMAGE_OSD_DEFAULT_DURATION;
916         if (duration > 1) duration += 1;
917
918         osd->icon_time[flag] = duration;
919
920         image_osd_update_schedule(osd, FALSE);
921         image_osd_timer_schedule(osd);
922 }
923 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */