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