use metadata_read_* functions where possible
[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
24 #include <math.h>
25
26 #define EXIF_BAR_SIZE_INCREMENT 48
27 #define EXIF_BAR_ARROW_SIZE 7
28
29 #define EXIF_BAR_CUSTOM_COUNT 20
30
31 #define BAR_EXIF_DATA_COLUMN_WIDTH 250
32
33 ExifUI ExifUIList[]={
34         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Camera")},
35         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("DateTime")},
36         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ShutterSpeed")},
37         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Aperture")},
38         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ExposureBias")},
39         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ISOSpeedRating")},
40         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("FocalLength")},
41         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("FocalLength35mmFilm")},
42         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Flash")},
43         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.ExposureProgram"},
44         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.MeteringMode"},
45         { 0, 0, EXIF_UI_IFSET,  "Exif.Photo.LightSource"},
46         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("ColorProfile")},
47         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("SubjectDistance")},
48         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("Resolution")},
49         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.Orientation"},
50         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("GPSPosition")},
51         { 0, 0, EXIF_UI_IFSET,  EXIF_FORMATTED("GPSAltitude")},
52         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.ImageDescription"},
53         { 0, 0, EXIF_UI_IFSET,  "Exif.Image.Copyright"},
54         { 0, 0, EXIF_UI_OFF,    NULL}
55 };
56
57
58 /*
59  *-------------------------------------------------------------------
60  * table util
61  *-------------------------------------------------------------------
62  */
63
64 static void table_add_line_custom(GtkWidget *table, gint x, gint y,
65                                   const gchar *text1, const gchar *text2,
66                                   GtkWidget **label1, GtkWidget **label2,
67                                   GtkWidget **remove)
68 {
69         GtkWidget *label;
70         gchar *buf;
71
72         buf = g_strconcat((text1) ? text1 : "fixme", ":", NULL);
73         if (!text2) text2 = "";
74
75         label = gtk_label_new(buf);
76         gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.0);
77         pref_label_bold(label, TRUE, FALSE);
78         gtk_table_attach(GTK_TABLE(table), label,
79                          x + 1, x + 2, y, y + 1,
80                          GTK_FILL, GTK_FILL,
81                          2, 2);
82         *label1 = label;
83
84         label = gtk_label_new(text2);
85         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
86         gtk_table_attach(GTK_TABLE(table), label,
87                          x + 2, x + 3, y, y + 1,
88                          GTK_FILL, GTK_FILL,
89                          2, 2);
90         *label2 = label;
91
92         if (remove)
93                 {
94                 *remove = gtk_check_button_new();
95                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(*remove), TRUE);
96
97                 gtk_table_attach(GTK_TABLE(table), *remove,
98                                  x, x + 1, y, y + 1,
99                                  GTK_FILL, GTK_FILL,
100                                  2, 2);
101                 }
102
103         g_free(buf);
104 }
105
106 static GtkWidget *table_add_line(GtkWidget *table, gint x, gint y,
107                                  const gchar *description, const gchar *text,
108                                  GtkWidget **keyret)
109 {
110         GtkWidget *key;
111         GtkWidget *label;
112
113         table_add_line_custom(table, x, y, description, text, &key, &label, NULL);
114         gtk_widget_show(key);
115         gtk_widget_show(label);
116         if (keyret) *keyret = key;
117
118         return label;
119 }
120
121
122 /*
123  *-------------------------------------------------------------------
124  * EXIF bar
125  *-------------------------------------------------------------------
126  */
127
128 typedef struct _ExifBar ExifBar;
129 struct _ExifBar
130 {
131         GtkWidget *vbox;
132         GtkWidget *scrolled;
133         GtkWidget *table;
134         GtkWidget *advanced_scrolled;
135         GtkWidget *listview;
136         GtkWidget **keys;
137         GtkWidget **labels;
138
139         GtkWidget *custom_sep;
140         GtkWidget *custom_name[EXIF_BAR_CUSTOM_COUNT];
141         GtkWidget *custom_value[EXIF_BAR_CUSTOM_COUNT];
142         GtkWidget *custom_remove[EXIF_BAR_CUSTOM_COUNT];
143
144         FileData *fd;
145
146         gint allow_search;
147 };
148
149 enum {
150         EXIF_ADVCOL_ENABLED = 0,
151         EXIF_ADVCOL_TAG,
152         EXIF_ADVCOL_NAME,
153         EXIF_ADVCOL_VALUE,
154         EXIF_ADVCOL_FORMAT,
155         EXIF_ADVCOL_ELEMENTS,
156         EXIF_ADVCOL_DESCRIPTION,
157         EXIF_ADVCOL_COUNT
158 };
159
160 static void bar_exif_sensitive(ExifBar *eb, gint enable)
161 {
162         gtk_widget_set_sensitive(eb->table, enable);
163         if (eb->advanced_scrolled) gtk_widget_set_sensitive(eb->advanced_scrolled, enable);
164 }
165
166 static gint bar_exif_row_enabled(const gchar *name)
167 {
168         GList *list;
169
170         if (!name) return FALSE;
171
172         list = history_list_get_by_key("exif_extras");
173         while (list)
174                 {
175                 if (strcmp(name, (gchar *)(list->data)) == 0) return TRUE;
176                 list = list->next;
177         }
178
179         return FALSE;
180 }
181
182 static void bar_exif_update(ExifBar *eb)
183 {
184         ExifData *exif;
185         gint i;
186
187         /* do we have any exif at all ? */
188         exif = exif_read_fd(eb->fd);
189
190         if (!exif)
191                 {
192                 bar_exif_sensitive(eb, FALSE);
193                 return;
194                 }
195         else
196                 {
197                 /* we will use high level functions so we can release it for now.
198                    it will stay in the cache */
199                 exif_free_fd(eb->fd, exif);
200                 exif = NULL;
201                 }
202         
203
204         bar_exif_sensitive(eb, TRUE);
205
206         if (GTK_WIDGET_VISIBLE(eb->scrolled))
207                 {
208                 GList *list;
209                 for (i = 0; ExifUIList[i].key; i++)
210                         {
211                         gchar *text;
212
213                         if (ExifUIList[i].current == EXIF_UI_OFF)
214                                 {
215                                 gtk_widget_hide(eb->labels[i]);
216                                 gtk_widget_hide(eb->keys[i]);
217                                 continue;
218                                 }
219                         text =  metadata_read_string(eb->fd, ExifUIList[i].key, METADATA_FORMATTED);
220                         if (ExifUIList[i].current == EXIF_UI_IFSET
221                             && (!text || !*text))
222                                 {
223                                 gtk_widget_hide(eb->labels[i]);
224                                 gtk_widget_hide(eb->keys[i]);
225                                 g_free(text);
226                                 continue;
227                                 }
228                         gtk_widget_show(eb->labels[i]);
229                         gtk_widget_show(eb->keys[i]);
230                         gtk_label_set_text(GTK_LABEL(eb->labels[i]), text);
231                         g_free(text);
232                         }
233
234                 list = g_list_last(history_list_get_by_key("exif_extras"));
235                 if (list)
236                         {
237                         gtk_widget_show(eb->custom_sep);
238                         }
239                 else
240                         {
241                         gtk_widget_hide(eb->custom_sep);
242                         }
243                 i = 0;
244                 while (list && i < EXIF_BAR_CUSTOM_COUNT)
245                         {
246                         gchar *text;
247                         gchar *name;
248                         gchar *buf;
249                         gchar *description;
250
251                         name = list->data;
252                         list = list->prev;
253                         
254                         text =  metadata_read_string(eb->fd, name, METADATA_FORMATTED);
255
256                         description = exif_get_tag_description_by_key(name);
257                         if (!description || *description == '\0') 
258                                 {
259                                 g_free(description);
260                                 description = g_strdup(name);
261                                 }
262                         buf = g_strconcat(description, ":", NULL);
263                         g_free(description);
264                         
265                         gtk_label_set_text(GTK_LABEL(eb->custom_name[i]), buf);
266                         g_free(buf);
267                         gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), text);
268                         g_free(text);
269
270                         gtk_widget_show(eb->custom_name[i]);
271                         gtk_widget_show(eb->custom_value[i]);
272                         g_object_set_data(G_OBJECT(eb->custom_remove[i]), "key", name);
273                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(eb->custom_remove[i]), TRUE);
274                         gtk_widget_show(eb->custom_remove[i]);
275
276                         i++;
277                         }
278                 while (i < EXIF_BAR_CUSTOM_COUNT)
279                         {
280                         g_object_set_data(G_OBJECT(eb->custom_remove[i]), "key", NULL);
281                         gtk_widget_hide(eb->custom_name[i]);
282                         gtk_widget_hide(eb->custom_value[i]);
283                         gtk_widget_hide(eb->custom_remove[i]);
284
285                         i++;
286                         }
287                 }
288
289         if (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled))
290                 {
291                 GtkListStore *store;
292                 GtkTreeIter iter;
293                 ExifData *exif_original;
294                 ExifItem *item;
295
296                 exif = exif_read_fd(eb->fd);
297                 if (!exif) return;
298                 
299                 exif_original = exif_get_original(exif);
300
301                 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
302                 gtk_list_store_clear(store);
303
304                 item = exif_get_first_item(exif_original);
305                 while (item)
306                         {
307                         gchar *tag;
308                         gchar *tag_name;
309                         gchar *text;
310                         gchar *utf8_text;
311                         const gchar *format;
312                         gchar *elements;
313                         gchar *description;
314
315                         tag = g_strdup_printf("0x%04x", exif_item_get_tag_id(item));
316                         tag_name = exif_item_get_tag_name(item);
317                         format = exif_item_get_format_name(item, TRUE);
318                         text = exif_item_get_data_as_text(item);
319                         utf8_text = utf8_validate_or_convert(text);
320                         g_free(text);
321                         elements = g_strdup_printf("%d", exif_item_get_elements(item));
322                         description = exif_item_get_description(item);
323                         if (!description || *description == '\0') 
324                                 {
325                                 g_free(description);
326                                 description = g_strdup(tag_name);
327                                 }
328
329                         gtk_list_store_append(store, &iter);
330                         gtk_list_store_set(store, &iter,
331                                         EXIF_ADVCOL_ENABLED, bar_exif_row_enabled(tag_name),
332                                         EXIF_ADVCOL_TAG, tag,
333                                         EXIF_ADVCOL_NAME, tag_name,
334                                         EXIF_ADVCOL_VALUE, utf8_text,
335                                         EXIF_ADVCOL_FORMAT, format,
336                                         EXIF_ADVCOL_ELEMENTS, elements,
337                                         EXIF_ADVCOL_DESCRIPTION, description, -1);
338                         g_free(tag);
339                         g_free(utf8_text);
340                         g_free(elements);
341                         g_free(description);
342                         g_free(tag_name);
343                         item = exif_get_next_item(exif_original);
344                         }
345                 exif_free_fd(eb->fd, exif);
346                 }
347
348 }
349
350 static void bar_exif_clear(ExifBar *eb)
351 {
352         gint i;
353
354         if (!GTK_WIDGET_SENSITIVE(eb->labels[0])) return;
355
356         for (i = 0; ExifUIList[i].key; i++)
357                 {
358                 gtk_label_set_text(GTK_LABEL(eb->labels[i]), "");
359                 }
360         for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
361                 {
362                 gtk_label_set_text(GTK_LABEL(eb->custom_value[i]), "");
363                 }
364
365         if (eb->listview)
366                 {
367                 GtkListStore *store;
368
369                 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(eb->listview)));
370                 gtk_list_store_clear(store);
371                 }
372 }
373
374 void bar_exif_set(GtkWidget *bar, FileData *fd)
375 {
376         ExifBar *eb;
377
378         eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
379         if (!eb) return;
380
381         /* store this, advanced view toggle needs to reload data */
382         file_data_unref(eb->fd);
383         eb->fd = file_data_ref(fd);
384
385         bar_exif_clear(eb);
386         bar_exif_update(eb);
387 }
388
389 static void bar_exif_row_toggled_cb(GtkCellRendererToggle *toggle, const gchar *path, gpointer data)
390 {
391         GtkWidget *listview = data;
392         GtkTreeModel *store;
393         GtkTreeIter iter;
394         GtkTreePath *tpath;
395         gchar *name = NULL;
396         gboolean active;
397
398         store = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
399
400         tpath = gtk_tree_path_new_from_string(path);
401         gtk_tree_model_get_iter(store, &iter, tpath);
402         gtk_tree_path_free(tpath);
403
404         gtk_tree_model_get(store, &iter, EXIF_ADVCOL_ENABLED, &active,
405                                          EXIF_ADVCOL_NAME, &name, -1);
406         active = (!active);
407
408         if (active &&
409             g_list_length(history_list_get_by_key("exif_extras")) >= EXIF_BAR_CUSTOM_COUNT)
410                 {
411                 active = FALSE;
412                 }
413
414         gtk_list_store_set(GTK_LIST_STORE(store), &iter, EXIF_ADVCOL_ENABLED, active, -1);
415
416         if (active)
417                 {
418                 history_list_add_to_key("exif_extras", name, EXIF_BAR_CUSTOM_COUNT);
419                 }
420         else
421                 {
422                 history_list_item_change("exif_extras", name, NULL);
423                 }
424
425         g_free(name);
426 }
427
428 static void bar_exif_remove_advanced_cb(GtkWidget *widget, gpointer data)
429 {
430         ExifBar *eb = data;
431         const gchar *key;
432
433         /* continue only if the toggle was deactivated */
434         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) return;
435
436         key = g_object_get_data(G_OBJECT(widget), "key");
437         if (!key) return;
438
439         history_list_item_change("exif_extras", key, NULL);
440
441         bar_exif_update(eb);
442 }
443
444 static void bar_exif_add_column_check(GtkWidget *listview, const gchar *title, gint n)
445 {
446         GtkTreeViewColumn *column;
447         GtkCellRenderer *renderer;
448
449         column = gtk_tree_view_column_new();
450         gtk_tree_view_column_set_title(column, title);
451         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
452
453         renderer = gtk_cell_renderer_toggle_new();
454         gtk_tree_view_column_pack_start(column, renderer, TRUE);
455         gtk_tree_view_column_add_attribute(column, renderer, "active", n);
456         gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
457
458         g_signal_connect(G_OBJECT(renderer), "toggled",
459                          G_CALLBACK(bar_exif_row_toggled_cb), listview);
460 }
461
462 static void bar_exif_add_column(GtkWidget *listview, const gchar *title, gint n, gint sizable)
463 {
464         GtkTreeViewColumn *column;
465         GtkCellRenderer *renderer;
466
467         column = gtk_tree_view_column_new();
468         gtk_tree_view_column_set_title(column, title);
469
470         if (sizable)
471                 {
472                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
473                 gtk_tree_view_column_set_fixed_width(column, BAR_EXIF_DATA_COLUMN_WIDTH);
474                 gtk_tree_view_column_set_resizable(column, TRUE);
475                 }
476         else
477                 {
478                 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
479                 }
480
481         renderer = gtk_cell_renderer_text_new();
482         gtk_tree_view_column_pack_start(column, renderer, TRUE);
483         gtk_tree_view_column_add_attribute(column, renderer, "text", n);
484         gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
485 }
486
487 static void bar_exif_advanced_build_view(ExifBar *eb)
488 {
489         GtkListStore *store;
490
491         if (eb->listview) return;
492
493         store = gtk_list_store_new(7, G_TYPE_BOOLEAN,
494                                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
495                                       G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
496         eb->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
497         g_object_unref(store);
498
499         gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(eb->listview), TRUE);
500         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(eb->listview), TRUE);
501
502         if (eb->allow_search)
503                 {
504                 gtk_tree_view_set_search_column(GTK_TREE_VIEW(eb->listview), EXIF_ADVCOL_NAME);
505                 }
506         else
507                 {
508                 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(eb->listview), FALSE);
509                 }
510
511         bar_exif_add_column_check(eb->listview, "", EXIF_ADVCOL_ENABLED);
512
513         bar_exif_add_column(eb->listview, _("Description"), EXIF_ADVCOL_DESCRIPTION, FALSE);
514         bar_exif_add_column(eb->listview, _("Value"), EXIF_ADVCOL_VALUE, TRUE);
515         bar_exif_add_column(eb->listview, _("Name"), EXIF_ADVCOL_NAME, FALSE);
516         bar_exif_add_column(eb->listview, _("Tag"), EXIF_ADVCOL_TAG, FALSE);
517         bar_exif_add_column(eb->listview, _("Format"), EXIF_ADVCOL_FORMAT, FALSE);
518         bar_exif_add_column(eb->listview, _("Elements"), EXIF_ADVCOL_ELEMENTS, FALSE);
519
520         eb->advanced_scrolled = gtk_scrolled_window_new(NULL, NULL);
521         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(eb->advanced_scrolled), GTK_SHADOW_IN);
522         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(eb->advanced_scrolled),
523                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
524         gtk_box_pack_start(GTK_BOX(eb->vbox), eb->advanced_scrolled, TRUE, TRUE, 0);
525         gtk_container_add(GTK_CONTAINER(eb->advanced_scrolled), eb->listview);
526         gtk_widget_show(eb->listview);
527 }
528
529 static void bar_exif_advanced_cb(GtkWidget *widget, gpointer data)
530 {
531         ExifBar *eb = data;
532         gint advanced;
533
534         advanced = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
535
536         if (advanced)
537                 {
538                 gtk_widget_hide(eb->scrolled);
539                 bar_exif_advanced_build_view(eb);
540                 gtk_widget_show(eb->advanced_scrolled);
541                 }
542         else
543                 {
544                 gtk_widget_hide(eb->advanced_scrolled);
545                 gtk_widget_show(eb->scrolled);
546                 }
547
548         bar_exif_update(eb);
549 }
550
551 gint bar_exif_is_advanced(GtkWidget *bar)
552 {
553         ExifBar *eb;
554
555         eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
556         if (!eb) return FALSE;
557
558         return (eb->advanced_scrolled && GTK_WIDGET_VISIBLE(eb->advanced_scrolled));
559 }
560
561 void bar_exif_close(GtkWidget *bar)
562 {
563         ExifBar *eb;
564
565         eb = g_object_get_data(G_OBJECT(bar), "bar_exif_data");
566         if (!eb) return;
567
568         gtk_widget_destroy(eb->vbox);
569 }
570
571 static void bar_exif_width(ExifBar *eb, gint val)
572 {
573         gint size;
574
575         size = eb->vbox->allocation.width;
576         size = CLAMP(size + val, EXIF_BAR_SIZE_INCREMENT * 2, EXIF_BAR_SIZE_INCREMENT * 16);
577
578         gtk_widget_set_size_request(eb->vbox, size, -1);
579         options->panels.exif.width = eb->vbox->allocation.width;
580 }
581
582 static void bar_exif_larger(GtkWidget *widget, gpointer data)
583 {
584         ExifBar *eb = data;
585
586         bar_exif_width(eb, EXIF_BAR_SIZE_INCREMENT);
587 }
588
589 static void bar_exif_smaller(GtkWidget *widget, gpointer data)
590 {
591         ExifBar *eb = data;
592
593         bar_exif_width(eb, -EXIF_BAR_SIZE_INCREMENT);
594 }
595
596 static void bar_exif_destroy(GtkWidget *widget, gpointer data)
597 {
598         ExifBar *eb = data;
599
600         g_free(eb->keys);
601         g_free(eb->labels);
602         file_data_unref(eb->fd);
603         g_free(eb);
604 }
605
606 GtkWidget *bar_exif_new(gint show_title, FileData *fd, gint advanced, GtkWidget *bounding_widget)
607 {
608         ExifBar *eb;
609         GtkWidget *table;
610         GtkWidget *viewport;
611         GtkWidget *hbox;
612         GtkWidget *button;
613         gint i;
614         gint exif_len;
615
616         for (exif_len = 0; ExifUIList[exif_len].key; exif_len++)
617               ;
618
619         eb = g_new0(ExifBar, 1);
620
621         eb->keys = g_new0(GtkWidget *, exif_len);
622         eb->labels = g_new0(GtkWidget *, exif_len);
623
624         eb->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP);
625         g_object_set_data(G_OBJECT(eb->vbox), "bar_exif_data", eb);
626         g_signal_connect_after(G_OBJECT(eb->vbox), "destroy",
627                                G_CALLBACK(bar_exif_destroy), eb);
628
629         eb->allow_search = !show_title;
630
631         if (show_title)
632                 {
633                 GtkWidget *box;
634                 GtkWidget *label;
635                 GtkWidget *button;
636                 GtkWidget *arrow;
637
638                 box = gtk_hbox_new(FALSE, 0);
639
640                 label = sizer_new(eb->vbox, bounding_widget, SIZER_POS_LEFT);
641                 sizer_set_limits(label, EXIF_BAR_SIZE_INCREMENT * 2, -1, -1 , -1);
642                 gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
643                 gtk_widget_show(label);
644
645                 label = gtk_label_new(_("Exif"));
646                 pref_label_bold(label, TRUE, FALSE);
647                 gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0);
648                 gtk_widget_show(label);
649
650                 button = gtk_button_new();
651                 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
652                 g_signal_connect(G_OBJECT(button), "clicked",
653                                  G_CALLBACK(bar_exif_smaller), eb);
654                 gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 0);
655                 arrow = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_NONE);
656                 gtk_widget_set_size_request(arrow, EXIF_BAR_ARROW_SIZE, EXIF_BAR_ARROW_SIZE);
657                 gtk_container_add(GTK_CONTAINER(button), arrow);
658                 gtk_widget_show(arrow);
659                 gtk_widget_show(button);
660
661                 button = gtk_button_new();
662                 gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
663                 g_signal_connect(G_OBJECT(button), "clicked",
664                                  G_CALLBACK(bar_exif_larger), eb);
665                 gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 0);
666                 arrow = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_NONE);
667                 gtk_widget_set_size_request(arrow, EXIF_BAR_ARROW_SIZE, EXIF_BAR_ARROW_SIZE);
668                 gtk_container_add(GTK_CONTAINER(button), arrow);
669                 gtk_widget_show(arrow);
670                 gtk_widget_show(button);
671
672                 gtk_box_pack_start(GTK_BOX(eb->vbox), box, FALSE, FALSE, 0);
673                 gtk_widget_show(box);
674                 }
675
676
677         table = gtk_table_new(3, exif_len + 1 + EXIF_BAR_CUSTOM_COUNT, FALSE);
678
679         eb->table = table;
680
681         for (i = 0; ExifUIList[i].key; i++)
682                 {
683                 gchar *text;
684
685                 text = exif_get_description_by_key(ExifUIList[i].key);
686                 eb->labels[i] = table_add_line(table, 0, i, text, NULL,
687                       &eb->keys[i]);
688                 g_free(text);
689                 }
690
691         eb->custom_sep = gtk_hseparator_new();
692         gtk_table_attach(GTK_TABLE(table), eb->custom_sep, 0, 3,
693                                            exif_len, exif_len + 1,
694                                            GTK_FILL, GTK_FILL, 2, 2);
695
696         for (i = 0; i < EXIF_BAR_CUSTOM_COUNT; i++)
697                 {
698                 table_add_line_custom(table, 0, exif_len + 1 + i,
699                                       "", "",  &eb->custom_name[i], &eb->custom_value[i],
700                                       &eb->custom_remove[i]);
701                 g_signal_connect(G_OBJECT(eb->custom_remove[i]), "clicked", 
702                                  G_CALLBACK(bar_exif_remove_advanced_cb), eb);
703                 }
704
705         eb->scrolled = gtk_scrolled_window_new(NULL, NULL);
706         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(eb->scrolled),
707                                        GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
708
709         viewport = gtk_viewport_new(NULL, NULL);
710         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
711         gtk_container_add(GTK_CONTAINER(eb->scrolled), viewport);
712         gtk_widget_show(viewport);
713
714         gtk_container_add(GTK_CONTAINER(viewport), table);
715         gtk_widget_show(table);
716
717         gtk_box_pack_start(GTK_BOX(eb->vbox), eb->scrolled, TRUE, TRUE, 0);
718
719         hbox = gtk_hbox_new(FALSE, PREF_PAD_SPACE);
720         gtk_box_pack_end(GTK_BOX(eb->vbox), hbox, FALSE, FALSE, 0);
721         gtk_widget_show(hbox);
722
723         button = gtk_check_button_new_with_label(_("Advanced view"));
724         if (advanced) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
725         g_signal_connect(G_OBJECT(button), "toggled",
726                          G_CALLBACK(bar_exif_advanced_cb), eb);
727         gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
728         gtk_widget_show(button);
729
730         eb->advanced_scrolled = NULL;
731         eb->listview = NULL;
732
733         if (advanced)
734                 {
735                 bar_exif_advanced_build_view(eb);
736                 gtk_widget_show(eb->advanced_scrolled);
737                 }
738         else
739                 {
740                 gtk_widget_show(eb->scrolled);
741                 }
742
743         eb->fd = file_data_ref(fd);
744         bar_exif_update(eb);
745
746         return eb->vbox;
747 }
748 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */