separated "normal" and advanced exif, "Normal" exif is now in the
[geeqie.git] / src / bar_exif.c
1 /*
2  * Geeqie
3  * (C) 2004 John Ellis
4  * Copyright (C) 2008 - 2009 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
14 #include "main.h"
15 #include "bar_exif.h"
16
17 #include "exif.h"
18 #include "metadata.h"
19 #include "filedata.h"
20 #include "history_list.h"
21 #include "misc.h"
22 #include "ui_misc.h"
23 #include "bar.h"
24
25
26 #include <math.h>
27
28 ExifUI ExifUIList[]={
29         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Camera")},
30         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("DateTime")},
31         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ShutterSpeed")},
32         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Aperture")},
33         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ExposureBias")},
34         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ISOSpeedRating")},
35         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("FocalLength")},
36         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("FocalLength35mmFilm")},
37         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Flash")},
38         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.ExposureProgram"},
39         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.MeteringMode"},
40         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.LightSource"},
41         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ColorProfile")},
42         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("SubjectDistance")},
43         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Resolution")},
44         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.Orientation"},
45         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("GPSPosition")},
46         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("GPSAltitude")},
47         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.ImageDescription"},
48         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.Copyright"},
49         { 0, 0, EXIF_UI_OFF,    NULL}
50 };
51
52
53 /*
54  *-------------------------------------------------------------------
55  * table util
56  *-------------------------------------------------------------------
57  */
58
59 static void table_add_line_custom(GtkWidget *table, gint x, gint y,
60                                   const gchar *text1, const gchar *text2,
61                                   GtkWidget **label1, GtkWidget **label2,
62                                   GtkWidget **remove)
63 {
64         GtkWidget *label;
65         gchar *buf;
66
67         buf = g_strconcat((text1) ? text1 : "fixme", ":", NULL);
68         if (!text2) text2 = "";
69
70         label = gtk_label_new(buf);
71         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.0);
72         pref_label_bold(label, TRUE, FALSE);
73         gtk_table_attach(GTK_TABLE(table), label,
74                          x + 1, x + 2, y, y + 1,
75                          GTK_FILL, GTK_FILL,
76                          2, 2);
77         *label1 = label;
78
79         label = gtk_label_new(text2);
80         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
81         gtk_table_attach(GTK_TABLE(table), label,
82                          x + 2, x + 3, y, y + 1,
83                          GTK_FILL, GTK_FILL,
84                          2, 2);
85         *label2 = label;
86
87         if (remove)
88                 {
89                 *remove = gtk_check_button_new();
90                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*remove), TRUE);
91
92                 gtk_table_attach(GTK_TABLE(table), *remove,
93                                  x, x + 1, y, y + 1,
94                                  GTK_FILL, GTK_FILL,
95                                  2, 2);
96                 }
97
98         g_free(buf);
99 }
100
101 static GtkWidget *table_add_line(GtkWidget *table, gint x, gint y,
102                                  const gchar *description, const gchar *text,
103                                  GtkWidget **keyret)
104 {
105         GtkWidget *key;
106         GtkWidget *label;
107
108         table_add_line_custom(table, x, y, description, text, &key, &label, NULL);
109         gtk_widget_show(key);
110         gtk_widget_show(label);
111         if (keyret) *keyret = key;
112
113         return label;
114 }
115
116
117 /*
118  *-------------------------------------------------------------------
119  * EXIF widget
120  *-------------------------------------------------------------------
121  */
122
123 typedef struct _PaneExifData PaneExifData;
124 struct _PaneExifData
125 {
126         PaneData pane;
127         GtkWidget *vbox;
128         GtkWidget *scrolled;
129         GtkWidget *table;
130         GtkWidget **keys;
131         GtkWidget **labels;
132
133         GtkWidget *custom_sep;
134         GtkWidget *custom_name[EXIF_BAR_CUSTOM_COUNT];
135         GtkWidget *custom_value[EXIF_BAR_CUSTOM_COUNT];
136         GtkWidget *custom_remove[EXIF_BAR_CUSTOM_COUNT];
137
138         FileData *fd;
139
140         gint allow_search;
141 };
142
143 static void bar_pane_exif_sensitive(PaneExifData *ped, gint enable)
144 {
145         gtk_widget_set_sensitive(ped->table, enable);
146 }
147
148 static void bar_pane_exif_update(PaneExifData *ped)
149 {
150         ExifData *exif;
151         gint i;
152         GList *list;
153
154         /* do we have any exif at all ? */
155         exif = exif_read_fd(ped->fd);
156
157         if (!exif)
158                 {
159                 bar_pane_exif_sensitive(ped, FALSE);
160                 return;
161                 }
162         else
163                 {
164                 /* we will use high level functions so we can release it for now.
165                    it will stay in the cache */
166                 exif_free_fd(ped->fd, exif);
167                 exif = NULL;
168                 }
169         
170
171         bar_pane_exif_sensitive(ped, TRUE);
172
173         for (i = 0; ExifUIList[i].key; i++)
174                 {
175                 gchar *text;
176
177                 if (ExifUIList[i].current == EXIF_UI_OFF)
178                         {
179                         gtk_widget_hide(ped->labels[i]);
180                         gtk_widget_hide(ped->keys[i]);
181                         continue;
182                         }
183                 text =  metadata_read_string(ped->fd, ExifUIList[i].key, METADATA_FORMATTED);
184                 if (ExifUIList[i].current == EXIF_UI_IFSET
185                     && (!text || !*text))
186                         {
187                         gtk_widget_hide(ped->labels[i]);
188                         gtk_widget_hide(ped->keys[i]);
189                         g_free(text);
190                         continue;
191                         }
192                 gtk_widget_show(ped->labels[i]);
193                 gtk_widget_show(ped->keys[i]);
194                 gtk_label_set_text(GTK_LABEL(ped->labels[i]), text);
195                 g_free(text);
196                 }
197
198         list = g_list_last(history_list_get_by_key("exif_extras"));
199         if (list)
200                 {
201                 gtk_widget_show(ped->custom_sep);
202                 }
203         else
204                 {
205                 gtk_widget_hide(ped->custom_sep);
206                 }
207         i = 0;
208         while (list && i < EXIF_BAR_CUSTOM_COUNT)
209                 {
210                 gchar *text;
211                 gchar *name;
212                 gchar *buf;
213                 gchar *description;
214
215                 name = list->data;
216                 list = list->prev;
217                 
218                 text =  metadata_read_string(ped->fd, name, METADATA_FORMATTED);
219
220                 description = exif_get_tag_description_by_key(name);
221                 if (!description || *description == '\0') 
222                         {
223                         g_free(description);
224                         description = g_strdup(name);
225                         }
226                 buf = g_strconcat(description, ":", NULL);
227                 g_free(description);
228                 
229                 gtk_label_set_text(GTK_LABEL(ped->custom_name[i]), buf);
230                 g_free(buf);
231                 gtk_label_set_text(GTK_LABEL(ped->custom_value[i]), text);
232                 g_free(text);
233
234                 gtk_widget_show(ped->custom_name[i]);
235                 gtk_widget_show(ped->custom_value[i]);
236                 g_object_set_data(G_OBJECT(ped->custom_remove[i]), "key", name);
237                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ped->custom_remove[i]), TRUE);
238                 gtk_widget_show(ped->custom_remove[i]);
239
240                 i++;
241                 }
242         while (i < EXIF_BAR_CUSTOM_COUNT)
243                 {
244                 g_object_set_data(G_OBJECT(ped->custom_remove[i]), "key", NULL);
245                 gtk_widget_hide(ped->custom_name[i]);
246                 gtk_widget_hide(ped->custom_value[i]);
247                 gtk_widget_hide(ped->custom_remove[i]);
248
249                 i++;
250                 }
251 }
252
253 static void bar_pane_exif_clear(PaneExifData *ped)
254 {
255         gint i;
256
257         if (!GTK_WIDGET_SENSITIVE(ped->labels[0])) return;
258
259         for (i = 0; ExifUIList[i].key; i++)
260                 {
261                 gtk_label_set_text(GTK_LABEL(ped->labels[i]), "");
262                 }
263         for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
264                 {
265                 gtk_label_set_text(GTK_LABEL(ped->custom_value[i]), "");
266                 }
267 }
268
269 void bar_pane_exif_set_fd(GtkWidget *widget, FileData *fd)
270 {
271         PaneExifData *ped;
272
273         ped = g_object_get_data(G_OBJECT(widget), "pane_data");
274         if (!ped) return;
275
276         /* store this, advanced view toggle needs to reload data */
277         file_data_unref(ped->fd);
278         ped->fd = file_data_ref(fd);
279
280         bar_pane_exif_clear(ped);
281         bar_pane_exif_update(ped);
282 }
283
284 static void bar_pane_exif_remove_advanced_cb(GtkWidget *widget, gpointer data)
285 {
286         PaneExifData *ped = data;
287         const gchar *key;
288
289         /* continue only if the toggle was deactivated */
290         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
291
292         key = g_object_get_data(G_OBJECT(widget), "key");
293         if (!key) return;
294
295         history_list_item_change("exif_extras", key, NULL);
296
297         bar_pane_exif_update(ped);
298 }
299
300 void bar_pane_exif_close(GtkWidget *widget)
301 {
302         PaneExifData *ped;
303
304         ped = g_object_get_data(G_OBJECT(widget), "pane_data");
305         if (!ped) return;
306
307         gtk_widget_destroy(ped->vbox);
308 }
309
310 static void bar_pane_exif_destroy(GtkWidget *widget, gpointer data)
311 {
312         PaneExifData *ped = data;
313
314         g_free(ped->keys);
315         g_free(ped->labels);
316         file_data_unref(ped->fd);
317         g_free(ped);
318 }
319
320 GtkWidget *bar_pane_exif_new(const gchar *title)
321 {
322         PaneExifData *ped;
323         GtkWidget *table;
324         GtkWidget *viewport;
325         GtkWidget *hbox;
326         gint i;
327         gint exif_len;
328
329         for (exif_len = 0; ExifUIList[exif_len].key; exif_len++)
330               ;
331
332         ped = g_new0(PaneExifData, 1);
333
334         ped->pane.pane_set_fd = bar_pane_exif_set_fd;
335         ped->pane.title = g_strdup(title);
336
337         ped->keys = g_new0(GtkWidget *, exif_len);
338         ped->labels = g_new0(GtkWidget *, exif_len);
339
340         ped->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
341         g_object_set_data(G_OBJECT(ped->vbox), "pane_data", ped);
342         g_signal_connect_after(G_OBJECT(ped->vbox), "destroy",
343                                G_CALLBACK(bar_pane_exif_destroy), ped);
344
345
346         table = gtk_table_new(3, exif_len + 1 + EXIF_BAR_CUSTOM_COUNT, FALSE);
347
348         ped->table = table;
349
350         for (i = 0; ExifUIList[i].key; i++)
351                 {
352                 gchar *text;
353
354                 text = exif_get_description_by_key(ExifUIList[i].key);
355                 ped->labels[i] = table_add_line(table, 0, i, text, NULL,
356                       &ped->keys[i]);
357                 g_free(text);
358                 }
359
360         ped->custom_sep = gtk_hseparator_new();
361         gtk_table_attach(GTK_TABLE(table), ped->custom_sep, 0, 3,
362                                            exif_len, exif_len + 1,
363                                            GTK_FILL, GTK_FILL, 2, 2);
364
365         for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
366                 {
367                 table_add_line_custom(table, 0, exif_len + 1 + i,
368                                       "", "",  &ped->custom_name[i], &ped->custom_value[i],
369                                       &ped->custom_remove[i]);
370                 g_signal_connect(G_OBJECT(ped->custom_remove[i]), "clicked", 
371                                  G_CALLBACK(bar_pane_exif_remove_advanced_cb), ped);
372                 }
373
374         ped->scrolled = gtk_scrolled_window_new(NULL, NULL);
375         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(ped->scrolled),
376                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER);
377
378         viewport = gtk_viewport_new(NULL, NULL);
379         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
380         gtk_container_add(GTK_CONTAINER(ped->scrolled), viewport);
381         gtk_widget_show(viewport);
382
383         gtk_container_add(GTK_CONTAINER(viewport), table);
384         gtk_widget_show(table);
385
386         gtk_box_pack_start(GTK_BOX(ped->vbox), ped->scrolled, TRUE, TRUE, 0);
387
388         hbox = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
389         gtk_box_pack_end(GTK_BOX(ped->vbox), hbox, FALSE, FALSE, 0);
390         gtk_widget_show(hbox);
391
392         gtk_widget_show(ped->scrolled);
393
394         gtk_widget_show(ped->vbox);
395
396         return ped->vbox;
397 }
398 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */