rewritten exif pane to support arbitrary number of entries
[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_OFF,    NULL}
31 };
32
33
34
35 /*
36  *-------------------------------------------------------------------
37  * EXIF widget
38  *-------------------------------------------------------------------
39  */
40
41 typedef struct _ExifEntry ExifEntry;
42 struct _ExifEntry
43 {
44         GtkWidget *hbox;
45         GtkWidget *title_label;
46         GtkWidget *value_label;
47
48         gchar *key;
49         gchar *title;
50         gboolean if_set;
51         gboolean auto_title;
52 };
53         
54         
55 typedef struct _PaneExifData PaneExifData;
56 struct _PaneExifData
57 {
58         PaneData pane;
59         GtkWidget *vbox;
60         GtkWidget *widget;
61         GtkSizeGroup *size_group;
62
63         FileData *fd;
64         GList *entries;
65 };
66
67 static void bar_pane_exif_update_entry(PaneExifData *ped, ExifEntry *ee, gboolean update_title);
68
69 static void bar_pane_exif_entry_destroy(GtkWidget *widget, gpointer data)
70 {
71         ExifEntry *ee = data;
72
73         g_free(ee->key);
74         g_free(ee->title);
75         g_free(ee);
76 }
77
78
79 static void bar_pane_exif_add_entry(PaneExifData *ped, const gchar *key, const gchar *title, gint if_set)
80 {
81         ExifEntry *ee = g_new0(ExifEntry, 1);
82         
83         ee->key = g_strdup(key);
84         if (title && title[0])
85                 {
86                 ee->title = g_strdup(title);
87                 }
88         else
89                 {
90                 ee->title = exif_get_description_by_key(key);
91                 ee->auto_title = TRUE;
92                 }
93                 
94         ee->if_set = if_set;
95         
96         ee->hbox = gtk_hbox_new(FALSE, 0);
97         g_signal_connect_after(G_OBJECT(ee->hbox), "destroy",
98                                G_CALLBACK(bar_pane_exif_entry_destroy), ee);
99         
100         ee->title_label = gtk_label_new(NULL);
101         gtk_misc_set_alignment(GTK_MISC(ee->title_label), 1.0, 0.0);
102         gtk_size_group_add_widget(ped->size_group, ee->title_label);
103         gtk_box_pack_start(GTK_BOX(ee->hbox), ee->title_label, FALSE, TRUE, 0);
104         gtk_widget_show(ee->title_label);
105         
106         ee->value_label = gtk_label_new(NULL);
107 //      gtk_label_set_width_chars(GTK_LABEL(ee->value_label), 20);
108         gtk_label_set_ellipsize(GTK_LABEL(ee->value_label), PANGO_ELLIPSIZE_END);
109 //      gtk_widget_set_size_request(ee->value_label, 100, -1);
110         gtk_misc_set_alignment(GTK_MISC(ee->value_label), 0.0, 0.0);
111         gtk_box_pack_start(GTK_BOX(ee->hbox), ee->value_label, TRUE, TRUE, 1);
112         gtk_widget_show(ee->value_label);
113         
114         gtk_box_pack_start(GTK_BOX(ped->vbox), ee->hbox, TRUE, TRUE, 0);
115         ped->entries = g_list_append(ped->entries, ee);
116         bar_pane_exif_update_entry(ped, ee, TRUE);
117 }
118         
119 static void bar_pane_exif_entry_update_title(ExifEntry *ee)
120 {
121         gchar *markup;
122
123         markup = g_markup_printf_escaped("<span size='small'>%s:</span>", (ee->title) ? ee->title : "fixme");
124         gtk_label_set_markup(GTK_LABEL(ee->title_label), markup);
125         g_free(markup);
126 }
127
128 static void bar_pane_exif_update_entry(PaneExifData *ped, ExifEntry *ee, gboolean update_title)
129 {
130         gchar *text =  metadata_read_string(ped->fd, ee->key, METADATA_FORMATTED);
131
132         if (ee->if_set && (!text || !*text))
133                 {
134                 gtk_label_set_text(GTK_LABEL(ee->value_label), NULL);
135                 gtk_widget_hide(ee->hbox);
136                 }
137         else
138                 {
139                 gtk_label_set_text(GTK_LABEL(ee->value_label), text);
140 #if GTK_CHECK_VERSION(2,12,0)
141                 gtk_widget_set_tooltip_text(ee->hbox, text);
142 #endif
143                 gtk_widget_show(ee->hbox);
144                 }
145                 
146         g_free(text);
147         
148         if (update_title) bar_pane_exif_entry_update_title(ee);
149 }
150
151 static void bar_pane_exif_update(PaneExifData *ped)
152 {
153         GList *work;
154
155 #if 0
156         ExifData *exif;
157         /* do we have any exif at all ? */
158         exif = exif_read_fd(ped->fd);
159
160         if (!exif)
161                 {
162                 bar_pane_exif_sensitive(ped, FALSE);
163                 return;
164                 }
165         else
166                 {
167                 /* we will use high level functions so we can release it for now.
168                    it will stay in the cache */
169                 exif_free_fd(ped->fd, exif);
170                 exif = NULL;
171                 }
172
173         bar_pane_exif_sensitive(ped, TRUE);
174 #endif  
175
176         work = ped->entries;
177         while (work)
178                 {
179                 ExifEntry *ee = work->data;
180                 work = work->next;
181                 
182                 bar_pane_exif_update_entry(ped, ee, FALSE);
183                 }
184 }
185
186 void bar_pane_exif_set_fd(GtkWidget *widget, FileData *fd)
187 {
188         PaneExifData *ped;
189
190         ped = g_object_get_data(G_OBJECT(widget), "pane_data");
191         if (!ped) return;
192
193         file_data_unref(ped->fd);
194         ped->fd = file_data_ref(fd);
195
196         bar_pane_exif_update(ped);
197 }
198
199 static void bar_pane_exif_entry_write_config(ExifEntry *ee, GString *outstr, gint indent)
200 {
201         WRITE_STRING("<entry\n");
202         indent++;
203         WRITE_CHAR(*ee, key);
204         if (!ee->auto_title) WRITE_CHAR(*ee, title);
205         WRITE_BOOL(*ee, if_set);
206         indent--;
207         WRITE_STRING("/>\n");
208 }
209
210 static void bar_pane_exif_write_config(GtkWidget *pane, GString *outstr, gint indent)
211 {
212         PaneExifData *ped;
213         GList *work;
214         
215         ped = g_object_get_data(G_OBJECT(pane), "pane_data");
216         if (!ped) return;
217
218         WRITE_STRING("<pane_exif\n");
219         indent++;
220         write_char_option(outstr, indent, "pane.title", gtk_label_get_text(GTK_LABEL(ped->pane.title)));
221         WRITE_BOOL(*ped, pane.expanded);
222         indent--;
223         WRITE_STRING(">\n");
224         indent++;
225         work = ped->entries;
226         while (work)
227                 {
228                 ExifEntry *ee = work->data;
229                 work = work->next;
230                 
231                 bar_pane_exif_entry_write_config(ee, outstr, indent);
232                 }
233         indent--;
234         WRITE_STRING("</pane_exif>\n");
235 }
236
237
238 void bar_pane_exif_close(GtkWidget *widget)
239 {
240         PaneExifData *ped;
241
242         ped = g_object_get_data(G_OBJECT(widget), "pane_data");
243         if (!ped) return;
244
245         gtk_widget_destroy(ped->vbox);
246 }
247
248 static void bar_pane_exif_destroy(GtkWidget *widget, gpointer data)
249 {
250         PaneExifData *ped = data;
251
252         g_list_free(ped->entries);
253         g_object_unref(ped->size_group);
254         file_data_unref(ped->fd);
255         g_free(ped);
256 }
257
258 GtkWidget *bar_pane_exif_new(const gchar *title, gboolean expanded, gboolean populate)
259 {
260         PaneExifData *ped;
261
262         ped = g_new0(PaneExifData, 1);
263
264         ped->pane.pane_set_fd = bar_pane_exif_set_fd;
265         ped->pane.pane_write_config = bar_pane_exif_write_config;
266         ped->pane.title = gtk_label_new(title);
267         ped->pane.expanded = expanded;
268
269         ped->size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
270         ped->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
271         ped->widget = ped->vbox;
272         g_object_set_data(G_OBJECT(ped->widget), "pane_data", ped);
273         g_signal_connect_after(G_OBJECT(ped->widget), "destroy",
274                                G_CALLBACK(bar_pane_exif_destroy), ped);
275
276
277         if (populate)
278                 {
279                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("Camera"), NULL, TRUE);
280                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("DateTime"), NULL, TRUE);
281                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("ShutterSpeed"), NULL, TRUE);
282                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("Aperture"), NULL, TRUE);
283                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("ExposureBias"), NULL, TRUE);
284                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("ISOSpeedRating"), NULL, TRUE);
285                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("FocalLength"), NULL, TRUE);
286                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("FocalLength35mmFilm"), NULL, TRUE);
287                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("Flash"), NULL, TRUE);
288                 bar_pane_exif_add_entry(ped, "Exif.Photo.ExposureProgram", NULL, TRUE);
289                 bar_pane_exif_add_entry(ped, "Exif.Photo.MeteringMode", NULL, TRUE);
290                 bar_pane_exif_add_entry(ped, "Exif.Photo.LightSource", NULL, TRUE);
291                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("ColorProfile"), NULL, TRUE);
292                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("SubjectDistance"), NULL, TRUE);
293                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("Resolution"), NULL, TRUE);
294                 bar_pane_exif_add_entry(ped, "Exif.Image.Orientation", NULL, TRUE);
295                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("GPSPosition"), NULL, TRUE);
296                 bar_pane_exif_add_entry(ped, EXIF_FORMATTED("GPSAltitude"), NULL, TRUE);
297                 bar_pane_exif_add_entry(ped, "Exif.Image.ImageDescription", NULL, TRUE);
298                 bar_pane_exif_add_entry(ped, "Exif.Image.Copyright", NULL, TRUE);
299                 }
300         
301         gtk_widget_show(ped->widget);
302
303         return ped->widget;
304 }
305
306 GtkWidget *bar_pane_exif_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
307 {
308         gchar *title = g_strdup(_("NoName"));
309         gboolean expanded = TRUE;
310
311         while (*attribute_names)
312                 {
313                 const gchar *option = *attribute_names++;
314                 const gchar *value = *attribute_values++;
315
316                 if (READ_CHAR_FULL("pane.title", title)) continue;
317                 if (READ_BOOL_FULL("pane.expanded", expanded)) continue;
318                 
319
320                 DEBUG_1("unknown attribute %s = %s", option, value);
321                 }
322         
323         return bar_pane_exif_new(title, expanded, FALSE);
324 }
325
326 void bar_pane_exif_entry_add_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
327 {
328         PaneExifData *ped;
329         gchar *key = NULL;
330         gchar *title = NULL;
331         gboolean if_set = TRUE;
332
333         ped = g_object_get_data(G_OBJECT(pane), "pane_data");
334         if (!ped) return;
335
336         while (*attribute_names)
337                 {
338                 const gchar *option = *attribute_names++;
339                 const gchar *value = *attribute_values++;
340
341                 if (READ_CHAR_FULL("key", key)) continue;
342                 if (READ_CHAR_FULL("title", title)) continue;
343                 if (READ_BOOL_FULL("if_set", if_set)) continue;
344                 
345
346                 DEBUG_1("unknown attribute %s = %s", option, value);
347                 }
348         if (key && key[0]) bar_pane_exif_add_entry(ped, key, title, if_set);
349 }
350
351
352 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */