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