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