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