1 /* -*- linux-c -*-
2 Copyright (C) 2004 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: file_info.c 1298 2014-05-19 12:53:11Z tszilagyi $
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <glib.h>
28 #include <glib-object.h>
29 #include <gdk/gdk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <gtk/gtk.h>
33
34 #ifdef HAVE_MOD
35 #include <libmodplug/modplug.h>
36 #include "decoder/dec_mod.h"
37 #endif /* HAVE_MOD */
38
39 #ifdef HAVE_WAVPACK
40 #include <wavpack/wavpack.h>
41 #include "decoder/dec_wavpack.h"
42 #endif /* HAVE_WAVPACK */
43
44 #ifdef HAVE_CDDA
45 #include "cdda.h"
46 #endif /* HAVE_CDDA */
47
48 #include "common.h"
49 #include "utils.h"
50 #include "utils_gui.h"
51 #include "cover.h"
52 #include "decoder/file_decoder.h"
53 #include "music_browser.h"
54 #include "store_file.h"
55 #include "gui_main.h"
56 #include "options.h"
57 #include "trashlist.h"
58 #include "i18n.h"
59 #include "metadata.h"
60 #include "metadata_api.h"
61 #include "metadata_id3v1.h"
62 #include "metadata_id3v2.h"
63 #include "file_info.h"
64
65
66 /* requested width of value display/edit widgets */
67 #define VAL_WIDGET_WIDTH 250
68
69 /* dimensions of cover thumbnail */
70 #define THUMB_SIZE 48
71
72 /* import destination codes */
73 enum {
74 IMPORT_DEST_ARTIST,
75 IMPORT_DEST_RECORD,
76 IMPORT_DEST_TITLE,
77 IMPORT_DEST_YEAR,
78 IMPORT_DEST_NUMBER,
79 IMPORT_DEST_COMMENT,
80 IMPORT_DEST_RVA
81 };
82
83
84 extern options_t options;
85
86 #define FI_MAXPAGES 256
87
88 typedef struct {
89 int tag;
90 GtkWidget * table;
91 int n_rows;
92 int n_cols;
93 GtkWidget * combo;
94 GSList * slist; /* list of insertable frames */
95 } pageidx_t;
96
97 typedef struct {
98 /* arguments to show_file_info */
99 GtkTreeModel * model;
100 GtkTreeIter iter_track;
101 fileinfo_model_func_t mfun;
102 int mindepth;
103 gboolean allow_ms_import;
104 gboolean display_cover;
105
106 /* entries containing displayed data */
107 GtkWidget * entry_name;
108 GtkWidget * entry_path;
109 GtkWidget * cover_image_area;
110 GtkWidget * entry_format;
111 GtkWidget * entry_length;
112 GtkWidget * entry_sr;
113 GtkWidget * entry_ch;
114 GtkWidget * entry_bw;
115 GtkWidget * entry_nsamples;
116 GtkWidget * entry_mode;
117
118 /* work data */
119 gboolean media_ok;
120 char * name;
121 char * filename;
122 decoder_t * dec;
123 int is_cdda;
124 fileinfo_t fileinfo;
125
126 int bail_out;
127 file_decoder_t * fdec;
128 metadata_t * meta;
129 trashlist_t * trash;
130 GtkWidget * info_window;
131 GtkWidget * event_box;
132 GtkWidget * cover_align;
133 GtkWidget * hbox;
134 GtkWidget * add_tag_table;
135 GtkWidget * button_table;
136 GtkWidget * prev_button;
137 GtkWidget * next_button;
138 GtkWidget * save_button;
139 GtkWidget * nb;
140 GtkWidget * combo;
141 int addable_tags; /* META_TAG_*, bitwise or-ed */
142 gint n_pages; /* number of notebook pages */
143 pageidx_t pageidx[FI_MAXPAGES];
144 int selected_tag;
145 int dirty; /* whether the dialog has unsaved changes */
146 gboolean cover_set_from_apic;
147
148 /* for MOD info */
149 GtkWidget * smp_instr_list;
150 GtkListStore * smp_instr_list_store;
151 } fi_t;
152
153 typedef struct {
154 fi_t * fi;
155 meta_frame_t * frame;
156 int dest_type; /* one of IMPORT_DEST_* */
157 } import_data_t;
158
159
160
161 typedef struct {
162 fi_t * fi;
163 char savefile[MAXLEN];
164 unsigned int image_size;
165 void * image_data;
166 GtkWidget * save_button;
167 } save_pic_t;
168
169 typedef struct {
170 fi_t * fi;
171 meta_frame_t * frame;
172 save_pic_t * save_pic;
173 } change_pic_t;
174
175
176 /* 'source widget' for APIC frames */
177 typedef struct {
178 GtkWidget * descr_entry;
179 GtkWidget * type_combo;
180 GtkWidget * mime_label;
181 GtkWidget * image;
182 } apic_source_t;
183
184
185 extern GtkWidget * main_window;
186 extern GtkTreeStore * music_store;
187 extern GtkWidget * music_tree;
188
189
190 #ifdef HAVE_MOD
191 void module_info_fill_page(fi_t * fi, meta_frame_t * frame, GtkWidget * vbox);
192 #endif /* HAVE_MOD */
193
194
195 gint fi_save(GtkWidget * widget, gpointer data);
196 void fi_procframe_ins(fi_t * fi, meta_frame_t * frame);
197 void fi_procframe_add_tag_page(fi_t * fi, meta_frame_t * frame);
198
199
200 fi_t *
fi_new(void)201 fi_new(void) {
202
203 fi_t * fi;
204 int i;
205
206 if ((fi = (fi_t *)calloc(1, sizeof(fi_t))) == NULL) {
207 fprintf(stderr, "error: fileinfo_new(): calloc error\n");
208 return NULL;
209 }
210
211 for (i = 0; i < FI_MAXPAGES; i++) {
212 fi->pageidx[i].tag = -1;
213 }
214 fi->selected_tag = -1;
215
216 return fi;
217 }
218
219 void
fi_unload(fi_t * fi)220 fi_unload(fi_t * fi) {
221 fi->media_ok = FALSE;
222 if (fi->save_button) {
223 if (GTK_IS_WIDGET(fi->save_button)) gtk_widget_destroy(fi->save_button);
224 fi->save_button = NULL;
225 }
226 if (fi->add_tag_table) {
227 if (GTK_IS_WIDGET(fi->add_tag_table)) gtk_widget_destroy(fi->add_tag_table);
228 fi->add_tag_table = NULL;
229 }
230
231 if (fi->fdec != NULL) {
232 file_decoder_delete(fi->fdec);
233 fi->fdec = NULL;
234 fi->meta = NULL;
235 }
236 free(fi->name);
237 free(fi->filename);
238
239 trashlist_free(fi->trash);
240 fi->trash = NULL;
241 fi->cover_set_from_apic = FALSE;
242 }
243
244 void
fi_delete(fi_t * fi)245 fi_delete(fi_t * fi) {
246
247 int i;
248
249 if (fi == NULL) return;
250
251 fi_unload(fi);
252
253 for (i = 0; i < FI_MAXPAGES; i++) {
254 g_slist_free(fi->pageidx[i].slist);
255 fi->pageidx[i].slist = NULL;
256 }
257 free(fi);
258 }
259
260
261 void
fi_mark_changed(fi_t * fi)262 fi_mark_changed(fi_t * fi) {
263
264 if (fi->dirty != 0)
265 return;
266
267 gtk_window_set_title(GTK_WINDOW(fi->info_window), _("*File info"));
268 fi->dirty = 1;
269 }
270
271
272 void
fi_mark_unchanged(fi_t * fi)273 fi_mark_unchanged(fi_t * fi) {
274
275 if (fi->dirty == 0)
276 return;
277
278 gtk_window_set_title(GTK_WINDOW(fi->info_window), _("File info"));
279 fi->dirty = 0;
280 }
281
282
283 import_data_t *
import_data_new(void)284 import_data_new(void) {
285
286 import_data_t * data;
287
288 if ((data = (import_data_t *)calloc(1, sizeof(import_data_t))) == NULL) {
289 fprintf(stderr, "error: import_data_new(): calloc error\n");
290 return NULL;
291 }
292 return data;
293 }
294
295
296 int
fi_close_dialog(fi_t * fi)297 fi_close_dialog(fi_t * fi) {
298
299 int ret;
300 GtkWidget * dialog = gtk_message_dialog_new(GTK_WINDOW(fi->info_window),
301 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
302 GTK_MESSAGE_WARNING,
303 GTK_BUTTONS_NONE,
304 _("There are unsaved changes to the file metadata."));
305
306 gtk_window_set_title(GTK_WINDOW(dialog), _("Warning"));
307 gtk_dialog_add_buttons(GTK_DIALOG(dialog),
308 _("Save and close"), 1,
309 _("Discard changes"), 2,
310 _("Do not close"), 0,
311 NULL);
312 gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
313
314 ret = aqualung_dialog_run(GTK_DIALOG(dialog));
315 gtk_widget_destroy(dialog);
316 return ret;
317 }
318
319
320 int
fi_can_close(fi_t * fi)321 fi_can_close(fi_t * fi) {
322
323 if (fi->dirty != 0) {
324 switch (fi_close_dialog(fi)) {
325 case 1: /* Save and close */
326 if (fi_save(NULL, fi)) {
327 fi_mark_unchanged(fi);
328 return TRUE;
329 } else {
330 return FALSE;
331 }
332 case 2: /* Discard changes */
333 fi_mark_unchanged(fi);
334 return TRUE;
335 default: /* Do not close */
336 return FALSE;
337 }
338 }
339 return TRUE;
340 }
341
342
343 gint
dismiss(GtkWidget * widget,gpointer data)344 dismiss(GtkWidget * widget, gpointer data) {
345
346 fi_t * fi = (fi_t *)data;
347
348 if (fi_can_close(fi) != TRUE) {
349 return TRUE;
350 }
351
352 unregister_toplevel_window(fi->info_window);
353 gtk_widget_destroy(fi->info_window);
354
355 fi_delete(fi);
356 return TRUE;
357 }
358
359
360 gint
info_window_close(GtkWidget * widget,GdkEventAny * event,gpointer data)361 info_window_close(GtkWidget * widget, GdkEventAny * event, gpointer data) {
362
363 fi_t * fi = (fi_t *)data;
364
365 if (fi_can_close(fi) != TRUE) {
366 return TRUE;
367 }
368
369 unregister_toplevel_window(fi->info_window);
370 gtk_widget_destroy(fi->info_window);
371 trashlist_free(fi->trash);
372
373 fi_delete(fi);
374 return TRUE;
375 }
376
377
378 gint
info_window_key_pressed(GtkWidget * widget,GdkEventKey * kevent,gpointer data)379 info_window_key_pressed(GtkWidget * widget, GdkEventKey * kevent, gpointer data) {
380
381 fi_t * fi = (fi_t *)data;
382 int page;
383
384 switch (kevent->keyval) {
385 case GDK_Escape:
386 dismiss(NULL, data);
387 return TRUE;
388 break;
389 case GDK_Return:
390 page = (gtk_notebook_get_current_page(GTK_NOTEBOOK(fi->nb)) + 1) % fi->n_pages;
391 gtk_notebook_set_current_page(GTK_NOTEBOOK(fi->nb), page);
392 break;
393 }
394 return FALSE;
395 }
396
397
398 int
fi_set_frame_from_source(fi_t * fi,meta_frame_t * frame)399 fi_set_frame_from_source(fi_t * fi, meta_frame_t * frame) {
400
401 char * parsefmt = meta_get_field_parsefmt(frame->type);
402 char parsefmt_esc[MAXLEN];
403
404 escape_percents(parsefmt, parsefmt_esc);
405 if (META_FIELD_TEXT(frame->type)) {
406 if (frame->field_val != NULL) {
407 free(frame->field_val);
408 }
409 if (frame->type == META_FIELD_GENRE) {
410 frame->field_val = gtk_combo_box_get_active_text(GTK_COMBO_BOX(frame->source));
411 } else {
412 frame->field_val = strdup(gtk_entry_get_text(GTK_ENTRY(frame->source)));
413 }
414 } else if (META_FIELD_INT(frame->type)) {
415 int val = 0;
416 const char * str = gtk_entry_get_text(GTK_ENTRY(frame->source));
417 if (sscanf(str, parsefmt, &val) < 1) {
418 char msg[MAXLEN];
419 snprintf(msg, MAXLEN-1,
420 _("Conversion error in field %s:\n"
421 "'%s' does not conform to format '%s'!"),
422 frame->field_name, str, "%s");
423 message_dialog(_("Error"),
424 fi->info_window, GTK_MESSAGE_ERROR,
425 GTK_BUTTONS_OK, NULL, msg, parsefmt_esc);
426 return -1;
427 } else {
428 frame->int_val = val;
429 }
430 } else if (META_FIELD_FLOAT(frame->type)) {
431 float val = 0;
432 const char * str = gtk_entry_get_text(GTK_ENTRY(frame->source));
433 if (sscanf(str, parsefmt, &val) < 1) {
434 char msg[MAXLEN];
435 snprintf(msg, MAXLEN-1,
436 _("Conversion error in field %s:\n"
437 "'%s' does not conform to format '%s'!"),
438 frame->field_name, str, "%s");
439 message_dialog(_("Error"),
440 fi->info_window, GTK_MESSAGE_ERROR,
441 GTK_BUTTONS_OK, NULL, msg, parsefmt_esc);
442 return -1;
443 } else {
444 frame->float_val = val;
445 }
446 } else if (META_FIELD_BIN(frame->type)) {
447 if (frame->type == META_FIELD_APIC) {
448 apic_source_t * source = (apic_source_t *)frame->source;
449 if (frame->field_val != NULL) {
450 free(frame->field_val);
451 }
452 frame->field_val = strdup(gtk_entry_get_text(GTK_ENTRY(source->descr_entry)));
453 frame->int_val = gtk_combo_box_get_active(GTK_COMBO_BOX(source->type_combo));
454 if (frame->length == 0) {
455 message_dialog(_("Error"),
456 fi->info_window, GTK_MESSAGE_ERROR,
457 GTK_BUTTONS_OK, NULL,
458 _("Attached Picture frame with no image set!\n"
459 "Please set an image or remove the frame."));
460 return -1;
461 }
462 }
463 }
464 return 0;
465 }
466
467
468 gint
fi_save(GtkWidget * widget,gpointer data)469 fi_save(GtkWidget * widget, gpointer data) {
470
471 fi_t * fi = (fi_t *)data;
472 metadata_t * meta = fi->meta;
473 meta_frame_t * frame = meta->root;
474 int status = 0;
475
476 while (frame != NULL) {
477 if (fi_set_frame_from_source(fi, frame) < 0) {
478 status = -1;
479 break;
480 }
481 frame = frame->next;
482 }
483
484 if (status != 0) {
485 return FALSE;
486 }
487
488 if (fi->fdec->meta_write != NULL) {
489 int ret;
490 ret = fi->fdec->meta_write(fi->fdec, fi->meta);
491 if (ret == META_ERROR_NONE) {
492 fi_mark_unchanged(fi);
493 return TRUE;
494 } else {
495 message_dialog(_("Error"),
496 fi->info_window, GTK_MESSAGE_ERROR,
497 GTK_BUTTONS_OK, NULL,
498 _("Failed to write metadata to file.\n"
499 "Reason: %s"),
500 metadata_strerror(ret));
501 return FALSE;
502 }
503 } else {
504 fprintf(stderr, "programmer error: fdec->meta_write == NULL\n");
505 }
506
507 return FALSE;
508 }
509
510
511 void
import_button_pressed(GtkWidget * widget,gpointer gptr_data)512 import_button_pressed(GtkWidget * widget, gpointer gptr_data) {
513
514 import_data_t * data = (import_data_t *)gptr_data;
515 fi_t * fi = data->fi;
516 meta_frame_t * frame = data->frame;
517 GtkTreeModel * model = fi->model;
518 GtkTreeIter iter_track = fi->iter_track;
519 GtkTreeIter record_iter;
520 GtkTreeIter artist_iter;
521 GtkTreePath * path;
522 char tmp[MAXLEN];
523
524 record_data_t * record_data;
525 track_data_t * track_data;
526
527 if (fi_set_frame_from_source(fi, frame) < 0) {
528 return;
529 }
530
531 switch (data->dest_type) {
532 case IMPORT_DEST_TITLE:
533 gtk_tree_store_set(music_store, &iter_track, MS_COL_NAME, frame->field_val, -1);
534 music_store_mark_changed(&iter_track);
535 break;
536 case IMPORT_DEST_RECORD:
537 gtk_tree_model_iter_parent(model, &record_iter, &iter_track);
538 gtk_tree_store_set(music_store, &record_iter, MS_COL_NAME, frame->field_val, -1);
539 music_store_mark_changed(&record_iter);
540 break;
541 case IMPORT_DEST_ARTIST:
542 gtk_tree_model_iter_parent(model, &record_iter, &iter_track);
543 gtk_tree_model_iter_parent(model, &artist_iter, &record_iter);
544 gtk_tree_store_set(music_store, &artist_iter, MS_COL_NAME, frame->field_val, -1);
545 gtk_tree_store_set(music_store, &artist_iter, MS_COL_SORT, frame->field_val, -1);
546 path = gtk_tree_model_get_path(model, &iter_track);
547 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(music_tree), path, NULL, TRUE, 0.5f, 0.0f);
548 music_store_mark_changed(&artist_iter);
549 break;
550 case IMPORT_DEST_YEAR:
551 gtk_tree_model_iter_parent(model, &record_iter, &iter_track);
552 gtk_tree_model_get(GTK_TREE_MODEL(music_store), &record_iter, MS_COL_DATA, &record_data, -1);
553 if (sscanf(frame->field_val, "%d", &record_data->year) < 1) {
554 char msg[MAXLEN];
555 snprintf(msg, MAXLEN-1,
556 _("Error converting field %s to Year:\n"
557 "'%s' is not an integer number!"),
558 frame->field_name, frame->field_val);
559 message_dialog(_("Error"),
560 fi->info_window, GTK_MESSAGE_ERROR,
561 GTK_BUTTONS_OK, NULL, msg);
562 return;
563 } else {
564 music_store_mark_changed(&record_iter);
565 }
566 break;
567 case IMPORT_DEST_NUMBER:
568 snprintf(tmp, MAXLEN-1, "%02d", frame->int_val);
569 gtk_tree_store_set(music_store, &iter_track, MS_COL_SORT, tmp, -1);
570 music_store_mark_changed(&iter_track);
571 break;
572 case IMPORT_DEST_COMMENT:
573 gtk_tree_model_get(model, &iter_track, MS_COL_DATA, &track_data, -1);
574 tmp[0] = '\0';
575 if (track_data->comment != NULL) {
576 strncat(tmp, track_data->comment, MAXLEN-1);
577 }
578 if ((tmp[strlen(tmp)-1] != '\n') && (tmp[0] != '\0')) {
579 strncat(tmp, "\n", MAXLEN-1);
580 }
581 strncat(tmp, frame->field_val, MAXLEN-1);
582 free_strdup(&track_data->comment, tmp);
583 music_store_mark_changed(&iter_track);
584 break;
585 case IMPORT_DEST_RVA:
586 gtk_tree_model_get(model, &iter_track, MS_COL_DATA, &track_data, -1);
587 track_data->rva = frame->float_val;
588 track_data->use_rva = 1;
589 music_store_mark_changed(&iter_track);
590 break;
591 }
592 }
593
594 int
lookup_page(fi_t * fi,int tag)595 lookup_page(fi_t * fi, int tag) {
596
597 int i;
598 for (i = 0; i < FI_MAXPAGES; i++) {
599 if (fi->pageidx[i].tag == tag) {
600 return i;
601 }
602 }
603 return -1;
604 }
605
606 void
fi_set_page(fi_t * fi)607 fi_set_page(fi_t * fi) {
608 if (fi->selected_tag > -1) { /* try to select first page with the same tag */
609 int idx = lookup_page(fi, fi->selected_tag);
610 if (idx > -1) {
611 gtk_notebook_set_current_page(GTK_NOTEBOOK(fi->nb), idx);
612 return;
613 }
614 }
615 /* fallback to default behaviour */
616 fi->n_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(fi->nb));
617 if (fi->n_pages > 1) {
618 gtk_notebook_set_current_page(GTK_NOTEBOOK(fi->nb), options.tags_tab_first ? 1 : 0);
619 }
620 }
621
622 int
fi_tabwidth(fi_t * fi,metadata_t * meta)623 fi_tabwidth(fi_t * fi, metadata_t * meta) {
624
625 /* tabwidth is 2, +1 if called from Music Store, +1 if editable */
626 int tabwidth = 2;
627 tabwidth += fi->allow_ms_import? 1 : 0;
628 tabwidth += meta->writable ? 1 : 0;
629 return tabwidth;
630 }
631
632
633 void
save_pic_button_pressed(GtkWidget * widget,gpointer data)634 save_pic_button_pressed(GtkWidget * widget, gpointer data) {
635
636 save_pic_t * save_pic = (save_pic_t *)data;
637 fi_t * fi = save_pic->fi;
638
639 GSList * lfiles = NULL;
640 char filename[MAXLEN];
641 char * dirname;
642
643 dirname = g_path_get_dirname(options.currdir);
644 snprintf(filename, MAXLEN-1, "%s/%s", dirname, save_pic->savefile);
645 g_free(dirname);
646
647 lfiles = file_chooser(_("Please specify the file to save the image to."),
648 fi->info_window,
649 GTK_FILE_CHOOSER_ACTION_SAVE,
650 FILE_CHOOSER_FILTER_NONE,
651 FALSE,
652 filename);
653
654 if (lfiles != NULL) {
655
656 FILE * f = fopen(filename, "wb");
657
658 g_slist_free(lfiles);
659
660 if (f == NULL) {
661 fprintf(stderr, "error: fopen() failed\n");
662 return;
663 }
664 if (fwrite(save_pic->image_data, 1, save_pic->image_size, f) != save_pic->image_size) {
665 fprintf(stderr, "fwrite() error\n");
666 return;
667 }
668 fclose(f);
669
670 strncpy(options.currdir, filename, MAXLEN-1);
671 }
672 }
673
674
675 void
save_pic_update(save_pic_t * save_pic,fi_t * fi,meta_frame_t * frame)676 save_pic_update(save_pic_t * save_pic, fi_t * fi, meta_frame_t * frame) {
677
678 int i, r;
679 char mtype[20];
680 char savefilename[256];
681
682 mtype[0] = '\0';
683 strcpy(savefilename, "picture.");
684 r = sscanf(frame->field_name, "image/%s", mtype);
685 if (r == 0) {
686 strncpy(mtype, frame->field_name, 19);
687 }
688 for (i = 0; mtype[i] != '\0'; i++) {
689 mtype[i] = tolower(mtype[i]);
690 }
691 if (mtype[0] == '\0') {
692 strcpy(mtype, "dat");
693 }
694 strncat(savefilename, mtype, 255);
695
696 save_pic->fi = fi;
697 strncpy(save_pic->savefile, savefilename, MAXLEN-1);
698 save_pic->image_size = frame->length;
699 save_pic->image_data = frame->data;
700
701 if (save_pic->image_size > 0) {
702 gtk_widget_set_sensitive(save_pic->save_button, TRUE);
703 } else {
704 gtk_widget_set_sensitive(save_pic->save_button, FALSE);
705 }
706 }
707
708
709 GtkWidget *
make_image_from_binary(meta_frame_t * frame)710 make_image_from_binary(meta_frame_t * frame) {
711
712 GdkPixbuf * pixbuf;
713 GdkPixbuf * pixbuf_scaled;
714 GtkWidget * image;
715 int width, height;
716 int new_width, new_height;
717
718 void * data = frame->data;
719 int length = frame->length;
720
721 GdkPixbufLoader * loader;
722
723 if (length == 0) {
724 return gtk_label_new(_("(no image)"));
725 }
726
727 if (strcmp(frame->field_name, "-->") == 0) {
728 /* display URL */
729 char * str = meta_id3v2_to_utf8(0x0/*ascii*/, data, length);
730 GtkWidget * label = gtk_label_new(str);
731 g_free(str);
732 return label;
733 }
734
735 loader = gdk_pixbuf_loader_new();
736 if (gdk_pixbuf_loader_write(loader, frame->data, frame->length, NULL) != TRUE) {
737 fprintf(stderr, "make_image_from_binary: failed to load image #1\n");
738 g_object_unref(loader);
739 return gtk_label_new(_("(error loading image)"));
740 }
741
742 if (gdk_pixbuf_loader_close(loader, NULL) != TRUE) {
743 fprintf(stderr, "make_image_from_binary: failed to load image #2\n");
744 g_object_unref(loader);
745 return gtk_label_new(_("(error loading image)"));
746 }
747
748 pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
749 width = gdk_pixbuf_get_width(pixbuf);
750 height = gdk_pixbuf_get_height(pixbuf);
751 new_width = (width > VAL_WIDGET_WIDTH) ? VAL_WIDGET_WIDTH : width;
752 new_height = ((double)new_width / (double)width) * height;
753 pixbuf_scaled = gdk_pixbuf_scale_simple(pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
754 image = gtk_image_new_from_pixbuf(pixbuf_scaled);
755 g_object_unref(pixbuf_scaled);
756 g_object_unref(loader);
757 return image;
758 }
759
760
761 void
change_pic_button_pressed(GtkWidget * widget,gpointer data)762 change_pic_button_pressed(GtkWidget * widget, gpointer data) {
763
764 change_pic_t * change_pic = (change_pic_t *)data;
765 save_pic_t * save_pic = change_pic->save_pic;
766 fi_t * fi = change_pic->fi;
767 meta_frame_t * frame = change_pic->frame;
768 apic_source_t * source = ((apic_source_t *)(frame->source));
769 GSList * lfiles = NULL;
770
771 char str[MAXLEN];
772 GdkPixbufFormat * pformat;
773 gchar ** mime_types;
774
775 GtkWidget * vbox; /* parent of image */
776
777 lfiles = file_chooser(_("Please specify the file to load the image from."),
778 fi->info_window,
779 GTK_FILE_CHOOSER_ACTION_OPEN,
780 FILE_CHOOSER_FILTER_NONE,
781 FALSE,
782 options.currdir);
783
784 if (lfiles != NULL) {
785 g_slist_free(lfiles);
786 } else {
787 return;
788 }
789
790 pformat = gdk_pixbuf_get_file_info(options.currdir, NULL, NULL);
791 if (pformat == NULL) {
792 char msg[MAXLEN];
793 snprintf(msg, MAXLEN-1, _("Could not load image from:\n%s"), options.currdir);
794 message_dialog(_("Error"), fi->info_window, GTK_MESSAGE_ERROR,
795 GTK_BUTTONS_OK, NULL, msg);
796 return;
797 }
798
799 if (frame->data != NULL) {
800 free(frame->data);
801 }
802 if (!g_file_get_contents(options.currdir, ((gchar **)(&frame->data)),
803 ((gsize *)(&frame->length)), NULL)) {
804 fprintf(stderr, "g_file_get_contents failed on %s\n", options.currdir);
805 return;
806 }
807
808 mime_types = gdk_pixbuf_format_get_mime_types(pformat);
809 if (mime_types[0] != NULL) {
810 if (frame->field_name != NULL) {
811 free(frame->field_name);
812 }
813 frame->field_name = strdup(mime_types[0]);
814 g_strfreev(mime_types);
815 } else {
816 fprintf(stderr, "error: no mime type for image %s\n", options.currdir);
817 g_strfreev(mime_types);
818 return;
819 }
820
821 vbox = gtk_widget_get_parent(source->image);
822 gtk_widget_destroy(source->image);
823 source->image = make_image_from_binary(frame);
824 gtk_widget_show(source->image);
825 gtk_container_add(GTK_CONTAINER(vbox), source->image);
826 snprintf(str, MAXLEN-1, _("MIME type: %s"), frame->field_name);
827 gtk_label_set_text(GTK_LABEL(source->mime_label), str);
828 /* update callback data for 'Save picture' */
829 save_pic_update(save_pic, fi, frame);
830
831 fi_mark_changed(fi);
832 }
833
834
835 GtkWidget *
fi_procframe_label_apic(fi_t * fi,meta_frame_t * frame)836 fi_procframe_label_apic(fi_t * fi, meta_frame_t * frame) {
837
838 metadata_t * meta = fi->meta;
839 apic_source_t * source;
840
841 char * pic_caption;
842 char str[MAXLEN];
843 GtkWidget * label_frame;
844 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
845 GtkWidget * hbox;
846 GtkWidget * label;
847 GtkWidget * button;
848
849 change_pic_t * change_pic;
850
851 save_pic_t * save_pic = (save_pic_t *)malloc(sizeof(save_pic_t));
852 if (save_pic == NULL)
853 return NULL;
854
855 trashlist_add(fi->trash, save_pic);
856
857 change_pic = (change_pic_t *)malloc(sizeof(change_pic_t));
858 if (change_pic == NULL)
859 return NULL;
860
861 trashlist_add(fi->trash, change_pic);
862 change_pic->fi = fi;
863 change_pic->frame = frame;
864 change_pic->save_pic = save_pic;
865
866 frame->source = calloc(1, sizeof(apic_source_t));
867 if (frame->source == NULL)
868 return NULL;
869 trashlist_add(fi->trash, frame->source);
870 source = ((apic_source_t *)(frame->source));
871
872 meta_get_fieldname(META_FIELD_APIC, &pic_caption);
873 snprintf(str, MAXLEN-1, "%s:", pic_caption);
874
875 label_frame = gtk_frame_new(pic_caption);
876 gtk_container_add(GTK_CONTAINER(label_frame), vbox);
877 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
878
879
880 hbox = gtk_hbox_new(FALSE, 0);
881 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
882 snprintf(str, MAXLEN-1, _("MIME type: %s"), frame->field_name);
883 source->mime_label = gtk_label_new(str);
884 gtk_box_pack_start(GTK_BOX(hbox), source->mime_label, FALSE, FALSE, 0);
885
886 hbox = gtk_hbox_new(FALSE, 0);
887 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
888 label = gtk_label_new(_("Picture type:"));
889 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
890
891 if (meta->writable) {
892 int i = 0;
893 char * type_str;
894 hbox = gtk_hbox_new(FALSE, 0);
895 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
896 source->type_combo = gtk_combo_box_new_text();
897 while (1) {
898 type_str = meta_id3v2_apic_type_to_string(i);
899 if (type_str == NULL) {
900 break;
901 }
902 gtk_combo_box_append_text(GTK_COMBO_BOX(source->type_combo), type_str);
903 ++i;
904 }
905 gtk_combo_box_set_active(GTK_COMBO_BOX(source->type_combo), frame->int_val);
906 gtk_box_pack_start(GTK_BOX(hbox), source->type_combo, TRUE, TRUE, 0);
907 } else {
908 hbox = gtk_hbox_new(FALSE, 0);
909 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
910 snprintf(str, MAXLEN-1, "%s",
911 meta_id3v2_apic_type_to_string(frame->int_val));
912 label = gtk_label_new(str);
913 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
914 }
915
916 hbox = gtk_hbox_new(FALSE, 0);
917 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
918 label = gtk_label_new(_("Description:"));
919 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
920
921 if (meta->writable) {
922 hbox = gtk_hbox_new(FALSE, 0);
923 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
924 source->descr_entry = gtk_entry_new();
925 gtk_entry_set_text(GTK_ENTRY(source->descr_entry), frame->field_val);
926 gtk_box_pack_start(GTK_BOX(hbox), source->descr_entry, TRUE, TRUE, 0);
927 } else {
928 hbox = gtk_hbox_new(FALSE, 0);
929 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
930 label = gtk_label_new((frame->field_val[0] == '\0') ?
931 _("(no description)") : frame->field_val);
932 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
933 }
934
935
936 hbox = gtk_hbox_new(TRUE, 0);
937 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
938
939 button = gui_stock_label_button(_("Change"), GTK_STOCK_OPEN);
940 gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 3);
941 if (meta->writable) {
942 g_signal_connect(G_OBJECT(button), "clicked",
943 G_CALLBACK(change_pic_button_pressed),
944 (gpointer)change_pic);
945 } else {
946 gtk_widget_set_sensitive(button, FALSE);
947 }
948
949 save_pic->save_button = gui_stock_label_button(_("Save"), GTK_STOCK_SAVE);
950 gtk_box_pack_start(GTK_BOX(hbox), save_pic->save_button, TRUE, TRUE, 3);
951 g_signal_connect(G_OBJECT(save_pic->save_button), "clicked",
952 G_CALLBACK(save_pic_button_pressed),
953 (gpointer)save_pic);
954
955 save_pic_update(save_pic, fi, frame);
956
957 return label_frame;
958 }
959
960
961 GtkWidget *
fi_procframe_label(fi_t * fi,meta_frame_t * frame)962 fi_procframe_label(fi_t * fi, meta_frame_t * frame) {
963
964 if (frame->type == META_FIELD_APIC) {
965 return fi_procframe_label_apic(fi, frame);
966 } else {
967 char str[MAXLEN];
968 GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
969 GtkWidget * label;
970 snprintf(str, MAXLEN-1, "%s:", frame->field_name);
971 label = gtk_label_new(str);
972 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
973 return hbox;
974 }
975 }
976
977
978 void
fi_entry_changed_cb(GtkEntry * entry,gpointer data)979 fi_entry_changed_cb(GtkEntry * entry, gpointer data) {
980
981 fi_t * fi = (fi_t *)data;
982 fi_mark_changed(fi);
983 }
984
985
986 gint
genre_cmp(gconstpointer a,gconstpointer b)987 genre_cmp(gconstpointer a, gconstpointer b) {
988
989 return strcmp(id3v1_genre_str_from_code(GPOINTER_TO_INT(a)),
990 id3v1_genre_str_from_code(GPOINTER_TO_INT(b)));
991 }
992
993
994 void
make_genre_combo(meta_frame_t * frame,GtkWidget ** widget,GtkWidget ** entry)995 make_genre_combo(meta_frame_t * frame, GtkWidget ** widget, GtkWidget ** entry) {
996
997 int i;
998 GtkWidget * combo = gtk_combo_box_entry_new_text();
999 GSList * list = NULL;
1000 GSList * _list;
1001
1002 for (i = 0; i < 256; i++) {
1003 char * genre = id3v1_genre_str_from_code(i);
1004 if (genre == NULL) {
1005 break;
1006 }
1007 list = g_slist_append(list, GINT_TO_POINTER(i));
1008 }
1009
1010 list = g_slist_sort(list, genre_cmp);
1011 _list = list;
1012 while (_list != NULL) {
1013 char * genre = id3v1_genre_str_from_code(GPOINTER_TO_INT(_list->data));
1014 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), genre);
1015 _list = g_slist_next(_list);
1016 }
1017 g_slist_free(list);
1018
1019 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(combo), 4);
1020
1021 *widget = combo;
1022 *entry = GTK_WIDGET(gtk_bin_get_child(GTK_BIN(combo)));
1023
1024 if (frame->field_val[0] == '\0') { /* set default genre if none present */
1025 gtk_entry_set_text(GTK_ENTRY(*entry), id3v1_genre_str_from_code(0));
1026 } else {
1027 gtk_entry_set_text(GTK_ENTRY(*entry), frame->field_val);
1028 }
1029
1030 /* for ID3v1, only predefined genres can be selected, no editing allowed */
1031 if (frame->tag == META_TAG_ID3v1) {
1032 gtk_widget_set_can_focus(*entry, FALSE);
1033 gtk_editable_set_editable(GTK_EDITABLE(*entry), FALSE);
1034 }
1035 }
1036
1037
1038 void
make_apic_widget(meta_frame_t * frame,GtkWidget ** widget,GtkWidget ** entry)1039 make_apic_widget(meta_frame_t * frame, GtkWidget ** widget, GtkWidget ** entry) {
1040
1041 GtkWidget * apic_frame = gtk_frame_new(NULL);
1042 GtkWidget * image = make_image_from_binary(frame);
1043 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
1044
1045 gtk_frame_set_shadow_type(GTK_FRAME(apic_frame), GTK_SHADOW_NONE);
1046 gtk_container_add(GTK_CONTAINER(apic_frame), vbox);
1047 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1048 gtk_box_pack_start(GTK_BOX(vbox), image, TRUE, TRUE, 0);
1049
1050 *widget = apic_frame;
1051 *entry = apic_frame;
1052 ((apic_source_t *)(frame->source))->image = image;
1053 }
1054
1055
1056 GtkWidget *
fi_procframe_entry(fi_t * fi,meta_frame_t * frame)1057 fi_procframe_entry(fi_t * fi, meta_frame_t * frame) {
1058
1059 metadata_t * meta = fi->meta;
1060 GtkWidget * widget = NULL;
1061 GtkWidget * entry = NULL;
1062 if (META_FIELD_BIN(frame->type)) {
1063 /* TODO create image/whatever widget, etc. */
1064 if (frame->type == META_FIELD_APIC) {
1065 make_apic_widget(frame, &widget, &entry);
1066 }
1067 } else if (META_FIELD_INT(frame->type)) {
1068 char str[MAXLEN];
1069 char * format = meta_get_field_renderfmt(frame->type);
1070 widget = entry = gtk_entry_new();
1071 snprintf(str, MAXLEN-1, format, frame->int_val);
1072 gtk_entry_set_text(GTK_ENTRY(entry), str);
1073 } else if (META_FIELD_FLOAT(frame->type)) {
1074 char str[MAXLEN];
1075 char * format = meta_get_field_renderfmt(frame->type);
1076 widget = entry = gtk_entry_new();
1077 snprintf(str, MAXLEN-1, format, frame->float_val);
1078 gtk_entry_set_text(GTK_ENTRY(entry), str);
1079 } else {
1080 if (meta->writable && (frame->type == META_FIELD_GENRE)) {
1081 make_genre_combo(frame, &widget, &entry);
1082 } else {
1083 widget = entry = gtk_entry_new();
1084 gtk_entry_set_text(GTK_ENTRY(entry), frame->field_val);
1085 }
1086 }
1087
1088 if ((META_FIELD_TEXT(frame->type)) ||
1089 (META_FIELD_INT(frame->type)) ||
1090 (META_FIELD_FLOAT(frame->type))) {
1091 if (!meta->writable) {
1092 gtk_widget_set_can_focus(entry, FALSE);
1093 gtk_editable_set_editable(GTK_EDITABLE(entry), FALSE);
1094 } else {
1095 g_signal_connect(G_OBJECT(widget), "changed",
1096 G_CALLBACK(fi_entry_changed_cb), (gpointer)fi);
1097 }
1098 gtk_widget_set_size_request(widget, VAL_WIDGET_WIDTH, -1);
1099 }
1100 return widget;
1101 }
1102
1103
1104 import_data_t *
make_import_data_from_frame(fi_t * fi,meta_frame_t * frame,char * label)1105 make_import_data_from_frame(fi_t * fi, meta_frame_t * frame, char * label) {
1106
1107 import_data_t * data = import_data_new();
1108 trashlist_add(fi->trash, data);
1109 data->fi = fi;
1110 data->frame = frame;
1111
1112 switch (frame->type) {
1113 case META_FIELD_TITLE:
1114 data->dest_type = IMPORT_DEST_TITLE;
1115 strcpy(label, _("Import as Title"));
1116 break;
1117 case META_FIELD_ARTIST:
1118 data->dest_type = IMPORT_DEST_ARTIST;
1119 strcpy(label, _("Import as Artist"));
1120 break;
1121 case META_FIELD_ALBUM:
1122 data->dest_type = IMPORT_DEST_RECORD;
1123 strcpy(label, _("Import as Record"));
1124 break;
1125 case META_FIELD_DATE:
1126 data->dest_type = IMPORT_DEST_YEAR;
1127 strcpy(label, _("Import as Year"));
1128 break;
1129 case META_FIELD_TRACKNO:
1130 data->dest_type = IMPORT_DEST_NUMBER;
1131 strcpy(label, _("Import as Track No."));
1132 break;
1133 case META_FIELD_RG_TRACK_GAIN:
1134 case META_FIELD_RG_ALBUM_GAIN:
1135 case META_FIELD_RVA2:
1136 data->dest_type = IMPORT_DEST_RVA;
1137 strcpy(label, _("Import as RVA"));
1138 break;
1139 default:
1140 data->dest_type = IMPORT_DEST_COMMENT;
1141 strcpy(label, _("Add to Comments"));
1142 break;
1143 }
1144
1145 return data;
1146 }
1147
1148
1149 GtkWidget *
fi_procframe_importbtn(fi_t * fi,meta_frame_t * frame)1150 fi_procframe_importbtn(fi_t * fi, meta_frame_t * frame) {
1151
1152 char label[MAXLEN];
1153 GtkWidget * button = gtk_button_new();
1154 g_signal_connect(G_OBJECT(button), "clicked",
1155 G_CALLBACK(import_button_pressed),
1156 (gpointer)make_import_data_from_frame(fi, frame, label));
1157 gtk_button_set_label(GTK_BUTTON(button), label);
1158 return button;
1159 }
1160
1161
1162 void
fi_fill_tagcombo(GtkComboBox * combo,int addable_tags)1163 fi_fill_tagcombo(GtkComboBox * combo, int addable_tags) {
1164
1165 int i;
1166 int tag = 1;
1167
1168 if (!GTK_IS_COMBO_BOX(combo))
1169 return;
1170
1171 for (i = 0; i < 100; i++) {
1172 gtk_combo_box_remove_text(combo, 0);
1173 }
1174
1175 if (addable_tags == 0) {
1176 gtk_widget_set_sensitive(GTK_WIDGET(combo), FALSE);
1177 return;
1178 }
1179
1180 gtk_widget_set_sensitive(GTK_WIDGET(combo), TRUE);
1181
1182 while (tag <= META_TAG_MAX) {
1183 if (addable_tags & tag) {
1184 gtk_combo_box_append_text(combo, meta_get_tagname(tag));
1185 }
1186 tag <<= 1;
1187 }
1188
1189 gtk_combo_box_set_active(combo, 0);
1190 }
1191
1192 gint
fi_fill_combo_cmp(gconstpointer a,gconstpointer b)1193 fi_fill_combo_cmp(gconstpointer a, gconstpointer b) {
1194
1195 int field1 = GPOINTER_TO_INT(a);
1196 int field2 = GPOINTER_TO_INT(b);
1197 char * str1;
1198 char * str2;
1199
1200 if (!meta_get_fieldname(field1, &str1)) {
1201 fprintf(stderr, "fi_fill_combo_cmp: programmer error #1\n");
1202 }
1203 if (!meta_get_fieldname(field2, &str2)) {
1204 fprintf(stderr, "fi_fill_combo_cmp: programmer error #2\n");
1205 }
1206
1207 return strcmp(str1, str2);
1208 }
1209
1210
1211 void
fi_fill_combo_foreach(gpointer data,gpointer user_data)1212 fi_fill_combo_foreach(gpointer data, gpointer user_data) {
1213
1214 int field = GPOINTER_TO_INT(data);
1215 char * str;
1216 GtkComboBox * combo = (GtkComboBox *)user_data;
1217 if (!meta_get_fieldname(field, &str)) {
1218 fprintf(stderr, "fi_fill_combo_foreach: programmer error\n");
1219 }
1220 gtk_combo_box_append_text(combo, str);
1221 }
1222
1223 void
fi_fill_combo(GtkComboBox * combo,GSList * slist)1224 fi_fill_combo(GtkComboBox * combo, GSList * slist) {
1225
1226 int i;
1227 GSList * sorted_list = g_slist_copy(slist);
1228 for (i = 0; i < 100; i++) {
1229 gtk_combo_box_remove_text(combo, 0);
1230 }
1231 sorted_list = g_slist_sort(sorted_list, fi_fill_combo_cmp);
1232 g_slist_foreach(sorted_list, fi_fill_combo_foreach, combo);
1233 g_slist_free(sorted_list);
1234 gtk_combo_box_set_active(combo, 0);
1235 }
1236
1237 typedef struct {
1238 fi_t * fi;
1239 meta_frame_t * frame;
1240 GtkWidget * label;
1241 GtkWidget * entry;
1242 GtkWidget * importbtn;
1243 GtkWidget * delbtn;
1244 } fi_del_t;
1245
1246 void
fi_del_button_pressed(GtkWidget * widget,gpointer data)1247 fi_del_button_pressed(GtkWidget * widget, gpointer data) {
1248
1249 fi_del_t * fi_del = (fi_del_t *)data;
1250 fi_t * fi = fi_del->fi;
1251 metadata_t * meta = fi_del->fi->meta;
1252 meta_frame_t * frame = fi_del->frame;
1253
1254 if (frame->flags & META_FIELD_UNIQUE) {
1255 int page = lookup_page(fi, frame->tag);
1256 GtkWidget * combo = fi->pageidx[page].combo;
1257 GSList * slist = fi->pageidx[page].slist;
1258 slist = g_slist_append(slist, GINT_TO_POINTER(frame->type));
1259 fi->pageidx[page].slist = slist;
1260 fi_fill_combo(GTK_COMBO_BOX(combo), slist);
1261 }
1262
1263 metadata_remove_frame(meta, frame);
1264 meta_frame_free(frame);
1265
1266 gtk_widget_destroy(fi_del->label);
1267 gtk_widget_destroy(fi_del->entry);
1268 if (fi_del->importbtn != NULL) {
1269 gtk_widget_destroy(fi_del->importbtn);
1270 }
1271 gtk_widget_destroy(fi_del->delbtn);
1272 fi_mark_changed(fi);
1273 }
1274
1275 GtkWidget *
fi_procframe_delbtn(fi_t * fi,meta_frame_t * frame,GtkWidget * label,GtkWidget * entry,GtkWidget * importbtn)1276 fi_procframe_delbtn(fi_t * fi, meta_frame_t * frame,
1277 GtkWidget * label, GtkWidget * entry, GtkWidget * importbtn) {
1278
1279 fi_del_t * fi_del;
1280 GtkWidget * button = gtk_button_new();
1281 gtk_button_set_image(GTK_BUTTON(button),
1282 gtk_image_new_from_stock(GTK_STOCK_DELETE,
1283 GTK_ICON_SIZE_MENU));
1284
1285 if (frame->flags & META_FIELD_MANDATORY) {
1286 gtk_widget_set_sensitive(button, FALSE);
1287 return button;
1288 }
1289
1290 fi_del = calloc(1, sizeof(fi_del_t));
1291 fi_del->fi = fi;
1292 fi_del->frame = frame;
1293 fi_del->label = label;
1294 fi_del->entry = entry;
1295 fi_del->importbtn = importbtn;
1296 fi_del->delbtn = button;
1297 trashlist_add(fi->trash, fi_del);
1298 g_signal_connect(G_OBJECT(button), "clicked",
1299 G_CALLBACK(fi_del_button_pressed),
1300 (gpointer)fi_del);
1301 return button;
1302 }
1303
1304
1305 typedef struct {
1306 fi_t * fi;
1307 int tag;
1308 } fi_add_t;
1309
1310
1311 void
fi_add_button_pressed(GtkWidget * widget,gpointer data)1312 fi_add_button_pressed(GtkWidget * widget, gpointer data) {
1313
1314 fi_add_t * fi_add = (fi_add_t *)data;
1315 fi_t * fi = fi_add->fi;
1316 metadata_t * meta = fi_add->fi->meta;
1317 int page = lookup_page(fi, fi_add->tag);
1318 GtkWidget * combo = fi->pageidx[page].combo;
1319 GSList * slist = fi->pageidx[page].slist;
1320
1321 meta_frame_t * frame = meta_frame_new();
1322 int type;
1323 char * str;
1324
1325 /* Create new frame */
1326 char * combo_entry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(combo));
1327 if (combo_entry == NULL) {
1328 return;
1329 }
1330
1331 type = meta_frame_type_from_name(combo_entry);
1332 g_free(combo_entry);
1333
1334 frame->tag = fi_add->tag;
1335 frame->type = type;
1336 frame->flags = meta_get_default_flags(fi_add->tag, type);
1337 if (meta_get_fieldname(type, &str)) {
1338 frame->field_name = strdup(str);
1339 } else {
1340 fprintf(stderr, "fi_add_button_pressed: programmer error\n");
1341 }
1342 if (options.metaedit_auto_clone) {
1343 metadata_clone_frame(meta, frame);
1344 }
1345 if (frame->field_val == NULL) {
1346 frame->field_val = strdup("");
1347 }
1348 frame->next = NULL;
1349
1350 metadata_add_frame(meta, frame);
1351
1352 if (frame->flags & META_FIELD_UNIQUE) {
1353 slist = g_slist_remove(slist, GINT_TO_POINTER(frame->type));
1354 fi->pageidx[page].slist = slist;
1355 fi_fill_combo(GTK_COMBO_BOX(combo), slist);
1356 }
1357
1358 fi_procframe_ins(fi, frame);
1359 fi_mark_changed(fi);
1360 }
1361
1362 GtkWidget *
fi_procframe_addbtn(fi_t * fi,int tag)1363 fi_procframe_addbtn(fi_t * fi, int tag) {
1364
1365 fi_add_t * fi_add;
1366 GtkWidget * button = gui_stock_label_button(_("Add"), GTK_STOCK_ADD);
1367
1368 fi_add = calloc(1, sizeof(fi_add_t));
1369 fi_add->fi = fi;
1370 fi_add->tag = tag;
1371 trashlist_add(fi->trash, fi_add);
1372 g_signal_connect(G_OBJECT(button), "clicked",
1373 G_CALLBACK(fi_add_button_pressed),
1374 (gpointer)fi_add);
1375 return button;
1376 }
1377
1378 void
fi_addtag_button_pressed(GtkWidget * widget,gpointer data)1379 fi_addtag_button_pressed(GtkWidget * widget, gpointer data) {
1380
1381 fi_t * fi = (fi_t *)data;
1382 metadata_t * meta = fi->meta;
1383 meta_frame_t * frame;
1384 int tag;
1385 char * combo_entry = gtk_combo_box_get_active_text(GTK_COMBO_BOX(fi->combo));
1386 if (combo_entry == NULL) {
1387 return;
1388 }
1389 frame = meta_frame_new();
1390 tag = frame->tag = meta_tag_from_name(combo_entry);
1391 g_free(combo_entry);
1392
1393 metadata_add_mandatory_frames(meta, frame->tag);
1394
1395 fi_procframe_add_tag_page(fi, frame);
1396 fi->addable_tags &= ~frame->tag;
1397 fi_fill_tagcombo(GTK_COMBO_BOX(fi->combo), fi->addable_tags);
1398 meta_frame_free(frame);
1399
1400 /* display fields, if any */
1401 frame = metadata_get_frame_by_tag(meta, tag, NULL);
1402 while (frame != NULL) {
1403 fi_procframe_ins(fi, frame);
1404 frame = metadata_get_frame_by_tag(meta, tag, frame);
1405 }
1406 fi_mark_changed(fi);
1407 }
1408
1409 GtkWidget *
fi_procframe_addtagbtn(fi_t * fi)1410 fi_procframe_addtagbtn(fi_t * fi) {
1411
1412 GtkWidget * button = gui_stock_label_button(_("Add"), GTK_STOCK_ADD);
1413 g_signal_connect(G_OBJECT(button), "clicked",
1414 G_CALLBACK(fi_addtag_button_pressed),
1415 (gpointer)fi);
1416 return button;
1417 }
1418
1419
1420 #ifdef HAVE_MOD
1421 void
fi_procframe_ins_modinfo(fi_t * fi,meta_frame_t * frame)1422 fi_procframe_ins_modinfo(fi_t * fi, meta_frame_t * frame) {
1423
1424 int page = lookup_page(fi, frame->tag);
1425 GtkWidget * table = fi->pageidx[page].table;
1426 GtkWidget * vbox = gtk_vbox_new(FALSE, 0);
1427
1428 module_info_fill_page(fi, frame, vbox);
1429 gtk_table_attach(GTK_TABLE(table), vbox, 0, 1, 0, 1,
1430 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
1431 gtk_widget_show_all(fi->nb);
1432 }
1433 #endif /* HAVE_MOD */
1434
1435
1436 void
fi_procframe_ins(fi_t * fi,meta_frame_t * frame)1437 fi_procframe_ins(fi_t * fi, meta_frame_t * frame) {
1438
1439 metadata_t * meta = fi->meta;
1440 int page = lookup_page(fi, frame->tag);
1441 GtkWidget * table = fi->pageidx[page].table;
1442 int n_rows = fi->pageidx[page].n_rows;
1443 int n_cols = fi->pageidx[page].n_cols;
1444 int col = 0;
1445
1446 GtkWidget * label = NULL;
1447 GtkWidget * entry = NULL;
1448 GtkWidget * importbtn = NULL;
1449 GtkWidget * delbtn = NULL;
1450
1451 if (frame->type == META_FIELD_HIDDEN) {
1452 return;
1453 }
1454
1455 #ifdef HAVE_MOD
1456 if (frame->type == META_FIELD_MODINFO) {
1457 fi_procframe_ins_modinfo(fi, frame);
1458 return;
1459 }
1460 #endif /* HAVE_MOD */
1461
1462 if (frame->type == META_FIELD_APIC) {
1463 /* only display first APIC found */
1464 meta_frame_t * first_apic = metadata_get_frame_by_type(fi->meta, META_FIELD_APIC, NULL);
1465 if (frame == first_apic &&
1466 (find_cover_filename(fi->filename) == NULL || !options.use_external_cover_first)) {
1467 display_cover_from_binary(fi->cover_image_area, fi->event_box, fi->cover_align,
1468 THUMB_SIZE, THUMB_SIZE, frame->data, frame->length, FALSE, TRUE);
1469 fi->cover_set_from_apic = TRUE;
1470 } else {
1471 display_cover(fi->cover_image_area, fi->event_box, fi->cover_align,
1472 THUMB_SIZE, THUMB_SIZE, fi->filename, FALSE, TRUE);
1473 }
1474 }
1475
1476 ++n_rows;
1477 fi->pageidx[page].n_rows = n_rows;
1478 gtk_table_resize(GTK_TABLE(table), n_rows, n_cols);
1479
1480 /* Field label */
1481 label = fi_procframe_label(fi, frame);
1482 gtk_table_attach(GTK_TABLE(table), label, col, col+1, n_rows-1, n_rows,
1483 GTK_FILL, GTK_FILL, 5, 3);
1484 ++col;
1485
1486 /* Field entry */
1487 entry = fi_procframe_entry(fi, frame);
1488 gtk_table_attach(GTK_TABLE(table), entry, col, col+1, n_rows-1, n_rows,
1489 GTK_EXPAND | GTK_FILL, GTK_FILL, 5, 3);
1490 if (frame->type != META_FIELD_APIC) {
1491 frame->source = entry;
1492 }
1493 ++col;
1494
1495 /* Import button */
1496 if (fi->allow_ms_import) {
1497 importbtn = fi_procframe_importbtn(fi, frame);
1498 gtk_table_attach(GTK_TABLE(table), importbtn, col, col+1, n_rows-1, n_rows,
1499 GTK_FILL, GTK_FILL, 5, 3);
1500 ++col;
1501 }
1502
1503 /* Delete button */
1504 if (meta->writable) {
1505 delbtn = fi_procframe_delbtn(fi, frame,
1506 label, entry, importbtn);
1507 gtk_table_attach(GTK_TABLE(table), delbtn, col, col+1, n_rows-1, n_rows,
1508 GTK_FILL, GTK_FILL, 5, 3);
1509 ++col;
1510 }
1511
1512 if (meta->writable && (frame->flags & META_FIELD_UNIQUE)) {
1513 GtkWidget * combo = fi->pageidx[page].combo;
1514 GSList * slist = fi->pageidx[page].slist;
1515 slist = g_slist_remove(slist, GINT_TO_POINTER(frame->type));
1516 fi->pageidx[page].slist = slist;
1517 fi_fill_combo(GTK_COMBO_BOX(combo), slist);
1518 }
1519
1520 gtk_widget_show_all(fi->nb);
1521 }
1522
1523 typedef struct {
1524 fi_t * fi;
1525 int tag;
1526 } fi_deltag_t;
1527
1528 void
fi_deltag_button_pressed(GtkWidget * widget,gpointer data)1529 fi_deltag_button_pressed(GtkWidget * widget, gpointer data) {
1530
1531 fi_deltag_t * fi_deltag = (fi_deltag_t *)data;
1532 fi_t * fi = fi_deltag->fi;
1533 int tag = fi_deltag->tag;
1534 metadata_t * meta = fi->meta;
1535 meta_frame_t * frame;
1536 int i;
1537
1538 /* Remove all frames with frame->tag == tag */
1539 frame = meta->root;
1540 while (frame != NULL) {
1541 if (frame->tag == tag) {
1542 meta_frame_t * f = frame->next;
1543 metadata_remove_frame(meta, frame);
1544 meta_frame_free(frame);
1545 frame = f;
1546 } else {
1547 frame = frame->next;
1548 }
1549 }
1550
1551 /* Remove notebook page and update fi->pageidx */
1552 for (i = FI_MAXPAGES-1; i >= 0; i--) {
1553 if (fi->pageidx[i].tag == tag) {
1554 int k;
1555 for (k = i; k < FI_MAXPAGES-1; k++) {
1556 fi->pageidx[k] = fi->pageidx[k+1];
1557 }
1558 fi->pageidx[FI_MAXPAGES-1].tag = -1;
1559 gtk_notebook_remove_page(GTK_NOTEBOOK(fi->nb), i);
1560 fi->n_pages--;
1561 break;
1562 }
1563 }
1564
1565 fi->addable_tags |= tag;
1566 fi_fill_tagcombo(GTK_COMBO_BOX(fi->combo), fi->addable_tags);
1567 fi_mark_changed(fi);
1568 }
1569
1570 GtkWidget *
fi_procframe_deltagbtn(fi_t * fi,int tag)1571 fi_procframe_deltagbtn(fi_t * fi, int tag) {
1572
1573 fi_deltag_t * fi_deltag;
1574 GtkWidget * button = gtk_button_new();
1575 gtk_button_set_image(GTK_BUTTON(button),
1576 gtk_image_new_from_stock(GTK_STOCK_DELETE,
1577 GTK_ICON_SIZE_MENU));
1578
1579 fi_deltag = calloc(1, sizeof(fi_deltag_t));
1580 fi_deltag->fi = fi;
1581 fi_deltag->tag = tag;
1582 trashlist_add(fi->trash, fi_deltag);
1583 g_signal_connect(G_OBJECT(button), "clicked",
1584 G_CALLBACK(fi_deltag_button_pressed),
1585 (gpointer)fi_deltag);
1586 return button;
1587 }
1588
1589 void
fi_procframe_add_tag_page(fi_t * fi,meta_frame_t * frame)1590 fi_procframe_add_tag_page(fi_t * fi, meta_frame_t * frame) {
1591
1592 metadata_t * meta = fi->meta;
1593 GtkWidget * vbox = gtk_vbox_new(FALSE, 4);
1594 GtkWidget * vbox_padding = gtk_vbox_new(FALSE, 0);
1595 GtkWidget * scrwin = gtk_scrolled_window_new(NULL, NULL);
1596 GtkWidget * table = gtk_table_new(0, fi_tabwidth(fi, meta), FALSE);
1597 GtkWidget * label = gtk_label_new(meta_get_tagname(frame->tag));
1598 GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
1599 GtkWidget * combo = gtk_combo_box_new_text();
1600 GtkWidget * addbtn, * delbtn;
1601 GSList * slist = meta_get_possible_fields(frame->tag);
1602
1603 gtk_box_pack_start(GTK_BOX(vbox_padding), table, TRUE, TRUE, 7);
1604 gtk_box_pack_start(GTK_BOX(vbox), scrwin, TRUE, TRUE, 0);
1605 gtk_widget_set_size_request(scrwin, -1, 275);
1606 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
1607 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1608 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrwin), GTK_SHADOW_NONE);
1609 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrwin), vbox_padding);
1610
1611 gtk_notebook_append_page(GTK_NOTEBOOK(fi->nb), vbox, label);
1612 fi->n_pages++;
1613 fi->pageidx[fi->n_pages-1].tag = frame->tag;
1614 fi->pageidx[fi->n_pages-1].table = table;
1615 fi->pageidx[fi->n_pages-1].combo = combo;
1616 fi->pageidx[fi->n_pages-1].slist = slist;
1617 fi->pageidx[fi->n_pages-1].n_rows = 0;
1618 fi->pageidx[fi->n_pages-1].n_cols = fi_tabwidth(fi, meta);
1619
1620 if (meta->writable) {
1621 addbtn = fi_procframe_addbtn(fi, frame->tag);
1622 gtk_box_pack_start(GTK_BOX(hbox), addbtn, FALSE, FALSE, 5);
1623
1624 label = gtk_label_new(_("field:"));
1625 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
1626
1627 fi_fill_combo(GTK_COMBO_BOX(combo), slist);
1628 gtk_box_pack_start(GTK_BOX(hbox), combo, FALSE, FALSE, 5);
1629
1630 delbtn = fi_procframe_deltagbtn(fi, frame->tag);
1631 gtk_box_pack_end(GTK_BOX(hbox), delbtn, FALSE, FALSE, 5);
1632
1633 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
1634
1635 fi->addable_tags &= ~frame->tag;
1636 fi_fill_tagcombo(GTK_COMBO_BOX(fi->combo), fi->addable_tags);
1637 }
1638 gtk_widget_show_all(fi->nb);
1639 }
1640
1641 void
fi_procframe(fi_t * fi,meta_frame_t * frame)1642 fi_procframe(fi_t * fi, meta_frame_t * frame) {
1643
1644 int page = lookup_page(fi, frame->tag);
1645 if (page == -1) {
1646 fi_procframe_add_tag_page(fi, frame);
1647 }
1648 fi_procframe_ins(fi, frame);
1649 }
1650
1651 typedef struct {
1652 metadata_t * meta;
1653 void * data;
1654 } fi_procmeta_wait_data_t;
1655
1656 void fi_procmeta(metadata_t * meta, void * data);
1657
1658 gboolean
fi_procmeta_wait(gpointer cb_data)1659 fi_procmeta_wait(gpointer cb_data) {
1660
1661 fi_procmeta_wait_data_t * wd = (fi_procmeta_wait_data_t *)cb_data;
1662 fi_procmeta(wd->meta, wd->data);
1663 free(wd);
1664 return FALSE;
1665 }
1666
1667 void
fi_procmeta(metadata_t * meta,void * data)1668 fi_procmeta(metadata_t * meta, void * data) {
1669
1670 fi_t * fi = (fi_t *)data;
1671 meta_frame_t * frame;
1672 int i;
1673
1674 if (fi->bail_out) {
1675 /* this condition signals that file_decoder_open in show_file_info has failed */
1676 fi_delete(fi);
1677 return;
1678 }
1679
1680 if ((fi->nb == NULL) || !GTK_IS_NOTEBOOK(fi->nb)) {
1681 fi_procmeta_wait_data_t * fi_procmeta_wait_data = calloc(1, sizeof(fi_procmeta_wait_data_t));
1682 fi_procmeta_wait_data->meta = meta;
1683 fi_procmeta_wait_data->data = data;
1684 aqualung_timeout_add(100, fi_procmeta_wait, (gpointer)fi_procmeta_wait_data);
1685 return;
1686 }
1687
1688 if (fi->meta == meta) {
1689 return;
1690 }
1691
1692 /* remove possible previous metadata pages from notebook */
1693 for (i = FI_MAXPAGES-1; i > 0; i--) {
1694 if (fi->pageidx[i].tag != -1) {
1695 gtk_notebook_remove_page(GTK_NOTEBOOK(fi->nb), i);
1696 fi->pageidx[i].tag = -1;
1697 }
1698 }
1699 fi->n_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(fi->nb));
1700
1701 if (fi->meta != NULL) {
1702 metadata_free(fi->meta);
1703 }
1704 fi->meta = meta;
1705 fi->addable_tags = meta->valid_tags;
1706 frame = meta->root;
1707
1708 if (fi->meta->writable && (fi->save_button == NULL)) {
1709 fi->save_button = gtk_button_new_from_stock(GTK_STOCK_SAVE);
1710 g_signal_connect(fi->save_button, "clicked",
1711 G_CALLBACK(fi_save), (gpointer)fi);
1712 gtk_table_attach(GTK_TABLE(fi->button_table), fi->save_button,
1713 0, 1, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
1714 gtk_widget_show_all(fi->info_window);
1715 }
1716
1717 if (fi->meta->writable && (fi->add_tag_table == NULL)) {
1718 GtkWidget * addbtn;
1719
1720 fi->add_tag_table = gtk_table_new(1, 3, FALSE);
1721 gtk_box_pack_start(GTK_BOX(fi->hbox), fi->add_tag_table, FALSE, TRUE, 2);
1722
1723 addbtn = fi_procframe_addtagbtn(fi);
1724 gtk_table_attach(GTK_TABLE(fi->add_tag_table), addbtn,
1725 0, 1, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
1726
1727 gtk_table_attach(GTK_TABLE(fi->add_tag_table), gtk_label_new(_("tag:")),
1728 1, 2, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
1729
1730 fi->combo = gtk_combo_box_new_text();
1731 fi_fill_tagcombo(GTK_COMBO_BOX(fi->combo), fi->addable_tags);
1732 gtk_table_attach(GTK_TABLE(fi->add_tag_table), fi->combo,
1733 2, 3, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
1734
1735 gtk_widget_show_all(fi->info_window);
1736 }
1737
1738 while (frame != NULL) {
1739 fi_procframe(fi, frame);
1740 frame = frame->next;
1741 }
1742
1743 fi_set_page(fi);
1744 }
1745
1746
1747 gboolean
fi_cover_press_button_cb(GtkWidget * widget,GdkEventButton * event,gpointer data)1748 fi_cover_press_button_cb (GtkWidget *widget, GdkEventButton *event, gpointer data) {
1749
1750 fi_t * fi = (fi_t *)data;
1751
1752 if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
1753 meta_frame_t * frame;
1754 frame = metadata_get_frame_by_type(fi->meta, META_FIELD_APIC, NULL);
1755 if (frame != NULL && (find_cover_filename(fi->filename) == NULL || !options.use_external_cover_first)) {
1756 display_zoomed_cover_from_binary(fi->info_window, fi->event_box, frame->data, frame->length);
1757 } else {
1758 display_zoomed_cover(fi->info_window, fi->event_box, (gchar *)fi->filename);
1759 }
1760 }
1761 return TRUE;
1762 }
1763
1764 void
fi_add_file_table_row(char * caption,GtkWidget ** entry,GtkWidget * table,int row)1765 fi_add_file_table_row(char * caption, GtkWidget ** entry, GtkWidget * table, int row) {
1766 GtkWidget * hbox = gtk_hbox_new(FALSE, 0);
1767 GtkWidget * label = gtk_label_new(caption);
1768 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1769 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, row, row+1, GTK_FILL, GTK_FILL, 5, 3);
1770 *entry = gtk_entry_new();
1771 gtk_widget_set_size_request(*entry, 350, -1);
1772 gtk_widget_set_can_focus(*entry, FALSE);
1773 gtk_editable_set_editable(GTK_EDITABLE(*entry), FALSE);
1774 gtk_table_attach(GTK_TABLE(table), *entry, 1, 2, row, row+1,
1775 (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), GTK_FILL, 5, 3);
1776 }
1777
1778 void
fi_set_common_entries(fi_t * fi)1779 fi_set_common_entries(fi_t * fi) {
1780 char str[MAXLEN];
1781 gchar * file_display;
1782
1783 if (!fi->media_ok) {
1784 if (GTK_IS_ENTRY(fi->entry_name)) gtk_entry_set_text(GTK_ENTRY(fi->entry_name), fi->name);
1785 if (GTK_IS_ENTRY(fi->entry_path)) gtk_entry_set_text(GTK_ENTRY(fi->entry_path), "(unable to open)");
1786 if (GTK_IS_ENTRY(fi->entry_format)) gtk_entry_set_text(GTK_ENTRY(fi->entry_format), "");
1787 if (GTK_IS_ENTRY(fi->entry_length)) gtk_entry_set_text(GTK_ENTRY(fi->entry_length), "");
1788 if (GTK_IS_ENTRY(fi->entry_sr)) gtk_entry_set_text(GTK_ENTRY(fi->entry_sr), "");
1789 if (GTK_IS_ENTRY(fi->entry_ch)) gtk_entry_set_text(GTK_ENTRY(fi->entry_ch), "");
1790 if (GTK_IS_ENTRY(fi->entry_bw)) gtk_entry_set_text(GTK_ENTRY(fi->entry_bw), "");
1791 if (GTK_IS_ENTRY(fi->entry_nsamples)) gtk_entry_set_text(GTK_ENTRY(fi->entry_nsamples), "");
1792 if (GTK_IS_ENTRY(fi->entry_mode)) gtk_entry_set_text(GTK_ENTRY(fi->entry_mode), "");
1793 return;
1794 }
1795
1796 /* Heading */
1797
1798 gtk_entry_set_text(GTK_ENTRY(fi->entry_name), fi->name);
1799
1800 file_display = g_filename_display_name(fi->filename);
1801 gtk_entry_set_text(GTK_ENTRY(fi->entry_path), file_display);
1802 g_free(file_display);
1803
1804 if (!fi->cover_set_from_apic) {
1805 if (options.show_cover_for_ms_tracks_only == TRUE) {
1806 if (fi->display_cover == TRUE) {
1807 display_cover(fi->cover_image_area, fi->event_box, fi->cover_align,
1808 THUMB_SIZE, THUMB_SIZE, fi->filename, TRUE, TRUE);
1809 } else {
1810 hide_cover_thumbnail();
1811 }
1812 } else {
1813 display_cover(fi->cover_image_area, fi->event_box, fi->cover_align,
1814 THUMB_SIZE, THUMB_SIZE, fi->filename, TRUE, TRUE);
1815 }
1816 }
1817
1818 /* Audio data */
1819
1820 gtk_entry_set_text(GTK_ENTRY(fi->entry_format), fi->fileinfo.format_str);
1821
1822 if (fi->fileinfo.total_samples == 0) {
1823 strcpy(str, "N/A");
1824 } else {
1825 sample2time(fi->fileinfo.sample_rate, fi->fileinfo.total_samples, str, 0);
1826 }
1827 gtk_entry_set_text(GTK_ENTRY(fi->entry_length), str);
1828
1829 sprintf(str, _("%ld Hz"), fi->fileinfo.sample_rate);
1830 gtk_entry_set_text(GTK_ENTRY(fi->entry_sr), str);
1831
1832 if (fi->fileinfo.is_mono) {
1833 strcpy(str, _("MONO"));
1834 } else {
1835 strcpy(str, _("STEREO"));
1836 }
1837 gtk_entry_set_text(GTK_ENTRY(fi->entry_ch), str);
1838
1839 if (fi->fileinfo.bps == 0) {
1840 strcpy(str, "N/A kbit/s");
1841 } else {
1842 format_bps_label(fi->fileinfo.bps, fi->fileinfo.format_flags, str);
1843 }
1844 gtk_entry_set_text(GTK_ENTRY(fi->entry_bw), str);
1845
1846 if (fi->fileinfo.total_samples == 0) {
1847 strcpy(str, "N/A");
1848 } else {
1849 sprintf(str, "%lld", fi->fileinfo.total_samples);
1850 }
1851 gtk_entry_set_text(GTK_ENTRY(fi->entry_nsamples), str);
1852
1853 #ifdef HAVE_WAVPACK
1854 if (!fi->is_cdda && fi->fdec && fi->fdec->file_lib == WAVPACK_LIB) {
1855 wavpack_pdata_t * pd = (wavpack_pdata_t *)fi->dec->pdata;
1856 int mode = WavpackGetMode(pd->wpc);
1857
1858 if ((mode & MODE_LOSSLESS) && (mode & MODE_WVC)) {
1859 strncpy(str, "Hybrid Lossless", MAXLEN-1);
1860 } else if (mode & MODE_LOSSLESS) {
1861 strncpy(str, "Lossless", MAXLEN-1);
1862 } else {
1863 strncpy(str, "Hybrid Lossy", MAXLEN-1);
1864 }
1865 cut_trailing_whitespace(str);
1866 gtk_entry_set_text(GTK_ENTRY(fi->entry_mode), str);
1867 }
1868 #endif /* HAVE_WAVPACK */
1869 }
1870
1871 /* Fill up internal data with values from referenced file.
1872 * Return TRUE if successful, FALSE on error.
1873 */
1874 gboolean
fi_media_init(fi_t * fi)1875 fi_media_init(fi_t * fi) {
1876
1877 fi->is_cdda = 0;
1878 fi->bail_out = 0;
1879 fi->trash = trashlist_new();
1880
1881 #ifdef HAVE_CDDA
1882 if (g_str_has_prefix(fi->filename, "CDDA ")) {
1883
1884 char device_path[CDDA_MAXLEN];
1885 long hash;
1886 int track;
1887 cdda_drive_t * drive;
1888
1889 if (sscanf(fi->filename, "CDDA %s %lX %u", device_path, &hash, &track) < 3) {
1890 return FALSE;
1891 }
1892
1893 drive = cdda_get_drive_by_device_path(device_path);
1894 if ((drive == NULL) || (drive->disc.hash == 0L)) {
1895 return FALSE;
1896 }
1897
1898 fi->is_cdda = 1;
1899
1900 fi->fileinfo.format_str = _("Audio CD");
1901 fi->fileinfo.sample_rate = 44100;
1902 fi->fileinfo.is_mono = 0;
1903 fi->fileinfo.format_flags = 0;
1904 fi->fileinfo.bps = 2*16*44100;
1905 fi->fileinfo.total_samples = (drive->disc.toc[track] - drive->disc.toc[track-1]) * 588;
1906 }
1907 #endif /* HAVE_CDDA */
1908
1909 if (!fi->is_cdda) {
1910 fi->fdec = file_decoder_new();
1911 if (fi->fdec == NULL) {
1912 return FALSE;
1913 }
1914
1915 file_decoder_set_meta_cb(fi->fdec, fi_procmeta, fi);
1916 if (file_decoder_open(fi->fdec, fi->filename) != 0) {
1917 fi->bail_out = 1;
1918 return FALSE;
1919 }
1920
1921 file_decoder_send_metadata(fi->fdec);
1922 fi->dec = (decoder_t *)fi->fdec->pdec;
1923
1924 fi->fileinfo.format_str = fi->dec->format_str;
1925 fi->fileinfo.sample_rate = fi->fdec->fileinfo.sample_rate;
1926 fi->fileinfo.is_mono = fi->fdec->fileinfo.is_mono;
1927 fi->fileinfo.format_flags = fi->fdec->fileinfo.format_flags;
1928 fi->fileinfo.bps = fi->fdec->fileinfo.bps;
1929 fi->fileinfo.total_samples = fi->fdec->fileinfo.total_samples;
1930 }
1931 return TRUE;
1932 }
1933
1934 void
fi_reload(fi_t * fi,GtkTreeIter iter)1935 fi_reload(fi_t * fi, GtkTreeIter iter) {
1936 int i;
1937
1938 fi->selected_tag = fi->pageidx[gtk_notebook_get_current_page(GTK_NOTEBOOK(fi->nb))].tag;
1939
1940 fi_unload(fi);
1941 fi->iter_track = iter;
1942 fi->mfun(fi->model, fi->iter_track, &fi->name, &fi->filename);
1943
1944 /* remove any metadata pages from notebook */
1945 while (gtk_notebook_get_n_pages(GTK_NOTEBOOK(fi->nb)) > 1) {
1946 gtk_notebook_remove_page(GTK_NOTEBOOK(fi->nb), 1);
1947 }
1948 fi->n_pages = 1;
1949 for (i = 1; i < FI_MAXPAGES; i++) {
1950 fi->pageidx[i].tag = FALSE;
1951 }
1952
1953 fi->media_ok = fi_media_init(fi);
1954 fi_set_common_entries(fi);
1955 }
1956
1957 gint
fi_prev(GtkWidget * widget,gpointer data)1958 fi_prev(GtkWidget * widget, gpointer data) {
1959 fi_t * fi = data;
1960 GtkTreeModel * model = fi->model;
1961 GtkTreeIter iter = fi->iter_track;
1962 GtkTreeIter prev;
1963
1964 if (fi_can_close(fi) != TRUE) {
1965 return TRUE;
1966 }
1967 if (!tree_model_prev_iter(model, &iter, &prev, fi->mindepth)) {
1968 return TRUE;
1969 }
1970 fi_reload(fi, prev);
1971 return TRUE;
1972 }
1973
1974 gint
fi_next(GtkWidget * widget,gpointer data)1975 fi_next(GtkWidget * widget, gpointer data) {
1976 fi_t * fi = data;
1977 GtkTreeModel * model = fi->model;
1978 GtkTreeIter iter = fi->iter_track;
1979 GtkTreeIter next;
1980
1981 if (fi_can_close(fi) != TRUE) {
1982 return TRUE;
1983 }
1984 if (!tree_model_next_iter(model, &iter, &next, fi->mindepth)) {
1985 return TRUE;
1986 }
1987 fi_reload(fi, next);
1988 return TRUE;
1989 }
1990
1991 void
show_file_info(GtkTreeModel * model,GtkTreeIter iter_track,fileinfo_model_func_t mfun,int mindepth,gboolean allow_ms_import,gboolean display_cover)1992 show_file_info(GtkTreeModel * model, GtkTreeIter iter_track,
1993 fileinfo_model_func_t mfun, int mindepth,
1994 gboolean allow_ms_import, gboolean display_cover) {
1995
1996 GtkWidget * vbox;
1997 GtkWidget * hbox_t;
1998 GtkWidget * table;
1999 GtkWidget * dismiss_btn;
2000
2001 GtkWidget * vbox_file;
2002 GtkWidget * label_file;
2003 GtkWidget * table_file;
2004
2005 fi_t * fi = fi_new();
2006 if (fi == NULL) {
2007 return;
2008 }
2009
2010 /* save arguments */
2011 fi->model = model;
2012 fi->iter_track = iter_track;
2013 fi->mfun = mfun;
2014 fi->mindepth = mindepth;
2015 fi->allow_ms_import = allow_ms_import;
2016 fi->display_cover = display_cover;
2017 mfun(fi->model, fi->iter_track, &fi->name, &fi->filename);
2018
2019 fi->info_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2020 register_toplevel_window(fi->info_window, TOP_WIN_SKIN | TOP_WIN_TRAY);
2021 gtk_window_set_title(GTK_WINDOW(fi->info_window), _("File info"));
2022 gtk_window_set_transient_for(GTK_WINDOW(fi->info_window), GTK_WINDOW(main_window));
2023 gtk_window_set_position(GTK_WINDOW(fi->info_window), GTK_WIN_POS_CENTER);
2024 gtk_window_set_resizable(GTK_WINDOW(fi->info_window), TRUE);
2025 g_signal_connect(G_OBJECT(fi->info_window), "delete_event",
2026 G_CALLBACK(info_window_close), (gpointer)fi);
2027 g_signal_connect(G_OBJECT(fi->info_window), "key_press_event",
2028 G_CALLBACK(info_window_key_pressed), (gpointer)fi);
2029 gtk_container_set_border_width(GTK_CONTAINER(fi->info_window), 5);
2030
2031 vbox = gtk_vbox_new(FALSE, 0);
2032 gtk_container_add(GTK_CONTAINER(fi->info_window), vbox);
2033
2034 hbox_t = gtk_hbox_new(FALSE, 0);
2035 gtk_box_pack_start(GTK_BOX(vbox), hbox_t, FALSE, FALSE, 5);
2036
2037 table = gtk_table_new(2, 2, FALSE);
2038 gtk_box_pack_start(GTK_BOX(hbox_t), table, TRUE, TRUE, 4);
2039
2040 fi_add_file_table_row(_("Track:"), &fi->entry_name, table, 0);
2041 fi_add_file_table_row(_("File:"), &fi->entry_path, table, 1);
2042
2043 fi->cover_align = gtk_alignment_new(0.5f, 0.5f, 0.0f, 0.0f);
2044 gtk_box_pack_start(GTK_BOX(hbox_t), fi->cover_align, FALSE, FALSE, 0);
2045 fi->cover_image_area = gtk_image_new();
2046 fi->event_box = gtk_event_box_new ();
2047 gtk_container_add(GTK_CONTAINER(fi->cover_align), fi->event_box);
2048 gtk_container_add (GTK_CONTAINER (fi->event_box), fi->cover_image_area);
2049 g_signal_connect(G_OBJECT(fi->event_box), "button_press_event",
2050 G_CALLBACK(fi_cover_press_button_cb), (gpointer)fi);
2051 fi->hbox = gtk_hbox_new(FALSE, 0);
2052 gtk_box_pack_end(GTK_BOX(vbox), fi->hbox, FALSE, FALSE, 5);
2053
2054 fi->nb = gtk_notebook_new();
2055 gtk_box_pack_start(GTK_BOX(vbox), fi->nb, TRUE, TRUE, 5);
2056
2057 /* Audio data notebook page */
2058
2059 vbox_file = gtk_vbox_new(FALSE, 4);
2060 table_file = gtk_table_new(6, 2, FALSE);
2061 gtk_box_pack_start(GTK_BOX(vbox_file), table_file, TRUE, TRUE, 10);
2062 label_file = gtk_label_new(_("Audio data"));
2063 fi->pageidx[0].tag = -1;
2064 gtk_notebook_append_page(GTK_NOTEBOOK(fi->nb), vbox_file, label_file);
2065 fi->n_pages = 1;
2066
2067 fi_add_file_table_row(_("Format:"), &fi->entry_format, table_file, 0);
2068 fi_add_file_table_row(_("Length:"), &fi->entry_length, table_file, 1);
2069 fi_add_file_table_row(_("Samplerate:"), &fi->entry_sr, table_file, 2);
2070 fi_add_file_table_row(_("Channel count:"), &fi->entry_ch, table_file, 3);
2071 fi_add_file_table_row(_("Bandwidth:"), &fi->entry_bw, table_file, 4);
2072 fi_add_file_table_row(_("Total samples:"), &fi->entry_nsamples, table_file, 5);
2073 #ifdef HAVE_WAVPACK
2074 if (!fi->is_cdda && fi->fdec && fi->fdec->file_lib == WAVPACK_LIB) {
2075 fi_add_file_table_row(_("Mode:"), &fi->entry_mode, table_file, 6);
2076 }
2077 #endif /* HAVE_WAVPACK */
2078
2079 /* end of notebook stuff */
2080 gtk_widget_grab_focus(fi->nb);
2081
2082 fi->button_table = gtk_table_new(1, 2, FALSE);
2083 gtk_box_pack_end(GTK_BOX(fi->hbox), fi->button_table, FALSE, TRUE, 2);
2084
2085 fi->prev_button = gui_stock_label_button(NULL, GTK_STOCK_GO_BACK);
2086 g_signal_connect(fi->prev_button, "clicked", G_CALLBACK(fi_prev), (gpointer)fi);
2087 gtk_table_attach(GTK_TABLE(fi->button_table), fi->prev_button,
2088 1, 2, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
2089
2090 fi->next_button = gui_stock_label_button(NULL, GTK_STOCK_GO_FORWARD);
2091 g_signal_connect(fi->next_button, "clicked", G_CALLBACK(fi_next), (gpointer)fi);
2092 gtk_table_attach(GTK_TABLE(fi->button_table), fi->next_button,
2093 2, 3, 0, 1, GTK_FILL, GTK_FILL, 3, 0);
2094
2095 dismiss_btn = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
2096 g_signal_connect(dismiss_btn, "clicked", G_CALLBACK(dismiss), (gpointer)fi);
2097 gtk_table_attach(GTK_TABLE(fi->button_table), dismiss_btn, 3, 4, 0, 1,
2098 GTK_FILL, GTK_FILL, 3, 0);
2099
2100 gtk_widget_show_all(fi->info_window);
2101
2102 fi->media_ok = fi_media_init(fi);
2103 fi_set_common_entries(fi);
2104 fi_set_page(fi);
2105
2106 /* fi_t object is freed in info_window destroy handlers */
2107 }
2108
2109
2110 #ifdef HAVE_MOD
2111 /*
2112 * type = 0 for sample list
2113 * type != 0 for instrument list
2114 */
2115 void
show_list(fi_t * fi,gint type)2116 show_list(fi_t * fi, gint type) {
2117
2118 GtkTreeIter iter;
2119 gint i, len;
2120 gchar temp[MAXLEN], number[MAXLEN];
2121 decoder_t * md_dec;
2122 mod_pdata_t * md_pd;
2123
2124 md_dec = (decoder_t *)(fi->fdec->pdec);
2125 md_pd = (mod_pdata_t *)md_dec->pdata;
2126
2127 if (type) {
2128 len = ModPlug_NumInstruments(md_pd->mpf);
2129 } else {
2130 len = ModPlug_NumSamples(md_pd->mpf);
2131 }
2132
2133 if (len) {
2134 gtk_list_store_clear(fi->smp_instr_list_store);
2135 for(i = 0; i < len; i++) {
2136 memset(temp, 0, MAXLEN-1);
2137
2138 if (type) {
2139 ModPlug_InstrumentName(md_pd->mpf, i, temp);
2140 } else {
2141 ModPlug_SampleName(md_pd->mpf, i, temp);
2142 }
2143
2144 sprintf(number, "%2d", i);
2145 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(fi->smp_instr_list_store), &iter, NULL, i);
2146 gtk_list_store_append(fi->smp_instr_list_store, &iter);
2147 gtk_list_store_set(fi->smp_instr_list_store, &iter, 0, number, 1, temp, -1);
2148 }
2149 }
2150 }
2151
2152 void
set_first_row(fi_t * fi)2153 set_first_row(fi_t * fi) {
2154
2155 GtkTreeIter iter;
2156 GtkTreePath * visible_path;
2157
2158 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(fi->smp_instr_list_store), &iter, NULL, 0);
2159 visible_path = gtk_tree_model_get_path(GTK_TREE_MODEL(fi->smp_instr_list_store), &iter);
2160 gtk_tree_view_set_cursor(GTK_TREE_VIEW(fi->smp_instr_list), visible_path, NULL, TRUE);
2161 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(fi->smp_instr_list), visible_path,
2162 NULL, TRUE, 1.0, 0.0);
2163 gtk_widget_grab_focus(GTK_WIDGET(fi->smp_instr_list));
2164 }
2165
2166 void
radio_buttons_cb(GtkToggleButton * toggle_button,gpointer data)2167 radio_buttons_cb(GtkToggleButton * toggle_button, gpointer data) {
2168
2169 fi_t * fi = (fi_t *)data;
2170
2171 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button))) {
2172 show_list(fi, 0);
2173 } else {
2174 show_list(fi, 1);
2175 }
2176 set_first_row(fi);
2177 }
2178
2179 static void
module_info_add_row(char * caption,GtkWidget ** mod_label,GtkWidget * table,int row)2180 module_info_add_row(char * caption, GtkWidget ** mod_label, GtkWidget * table, int row) {
2181 GtkWidget * label = gtk_label_new(caption);
2182 gtk_widget_show(label);
2183 gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
2184 (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
2185 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
2186
2187 *mod_label = gtk_label_new("");
2188 gtk_widget_show(*mod_label);
2189 gtk_table_attach(GTK_TABLE(table), *mod_label, 1, 2, row, row+1,
2190 (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(0), 0, 0);
2191 }
2192
2193 void
module_info_fill_page(fi_t * fi,meta_frame_t * frame,GtkWidget * vbox)2194 module_info_fill_page(fi_t * fi, meta_frame_t * frame, GtkWidget * vbox) {
2195
2196 mod_info * mdi = (mod_info *)frame->data;
2197
2198 gchar *a_type[] = {
2199 "None", "MOD", "S3M", "XM", "MED", "MTM", "IT", "669",
2200 "ULT", "STM", "FAR", "WAV", "AMF", "AMS", "DSM", "MDL",
2201 "OKT", "MID", "DMF", "PTM", "DBM", "MT2", "AMF0", "PSM",
2202 "J2B", "UMX"
2203 };
2204
2205 gint i, n;
2206 gchar temp[MAXLEN];
2207 GtkWidget *table;
2208 GtkWidget *label;
2209 GtkWidget *mod_type_label;
2210 GtkWidget *mod_channels_label;
2211 GtkWidget *mod_patterns_label;
2212 GtkWidget *mod_samples_label;
2213 GtkWidget *mod_instruments_label;
2214 GtkWidget *vseparator;
2215 GtkWidget *hbox2;
2216 GtkWidget *vbox2;
2217 GtkWidget *vbox3;
2218 GtkWidget *samples_radiobutton = NULL;
2219 GtkWidget *instruments_radiobutton = NULL;
2220 GtkWidget *scrolledwindow;
2221
2222 GtkCellRenderer *renderer;
2223 GtkTreeViewColumn *column;
2224
2225 hbox2 = gtk_hbox_new (FALSE, 0);
2226 gtk_widget_show (hbox2);
2227 gtk_box_pack_start (GTK_BOX (vbox), hbox2, TRUE, TRUE, 0);
2228
2229 vbox2 = gtk_vbox_new (FALSE, 0);
2230 gtk_widget_show (vbox2);
2231 gtk_box_pack_start (GTK_BOX (hbox2), vbox2, FALSE, FALSE, 0);
2232
2233 if (mdi->instruments) {
2234 table = gtk_table_new (5, 2, FALSE);
2235 gtk_widget_show (table);
2236 gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
2237 gtk_container_set_border_width (GTK_CONTAINER (table), 8);
2238 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
2239 gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2240
2241 module_info_add_row(_("Type:"), &mod_type_label, table, 0);
2242 module_info_add_row(_("Channels:"), &mod_channels_label, table, 1);
2243 module_info_add_row(_("Patterns:"), &mod_patterns_label, table, 2);
2244 module_info_add_row(_("Samples:"), &mod_samples_label, table, 3);
2245 module_info_add_row(_("Instruments:"), &mod_instruments_label, table, 4);
2246
2247 sprintf(temp, "%d", mdi->instruments);
2248 gtk_label_set_text (GTK_LABEL(mod_instruments_label), temp);
2249
2250 table = gtk_table_new (2, 1, FALSE);
2251 gtk_widget_show (table);
2252 gtk_box_pack_end (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
2253 gtk_container_set_border_width (GTK_CONTAINER (table), 8);
2254 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
2255
2256 samples_radiobutton = gtk_radio_button_new_with_mnemonic (NULL, _("Samples"));
2257 gtk_widget_show (samples_radiobutton);
2258 gtk_table_attach (GTK_TABLE (table), samples_radiobutton, 0, 1, 0, 1,
2259 (GtkAttachOptions) (GTK_FILL | GTK_EXPAND),
2260 (GtkAttachOptions) (0), 0, 0);
2261 g_signal_connect(G_OBJECT(samples_radiobutton), "toggled",
2262 G_CALLBACK(radio_buttons_cb), (gpointer)fi);
2263
2264 instruments_radiobutton = gtk_radio_button_new_with_mnemonic_from_widget (GTK_RADIO_BUTTON(samples_radiobutton), _("Instruments"));
2265 gtk_widget_show (instruments_radiobutton);
2266 gtk_table_attach (GTK_TABLE (table), instruments_radiobutton, 0, 1, 1, 2,
2267 (GtkAttachOptions) (GTK_FILL),
2268 (GtkAttachOptions) (0), 0, 0);
2269 } else {
2270 table = gtk_table_new (4, 2, FALSE);
2271 gtk_widget_show (table);
2272 gtk_box_pack_start (GTK_BOX (vbox2), table, FALSE, FALSE, 0);
2273 gtk_container_set_border_width (GTK_CONTAINER (table), 8);
2274 gtk_table_set_row_spacings (GTK_TABLE (table), 4);
2275 gtk_table_set_col_spacings (GTK_TABLE (table), 4);
2276
2277 module_info_add_row(_("Type:"), &mod_type_label, table, 0);
2278 module_info_add_row(_("Channels:"), &mod_channels_label, table, 1);
2279 module_info_add_row(_("Patterns:"), &mod_patterns_label, table, 2);
2280 module_info_add_row(_("Samples:"), &mod_samples_label, table, 3);
2281 module_info_add_row(_("Instruments:"), &mod_instruments_label, table, 4);
2282 }
2283
2284 n = mdi->type;
2285 i = 0;
2286
2287 while (n > 0) { /* calculate module type index */
2288 n >>= 1;
2289 i++;
2290 }
2291
2292 gtk_label_set_text (GTK_LABEL(mod_type_label), a_type[i]);
2293 sprintf(temp, "%d", mdi->channels);
2294 gtk_label_set_text (GTK_LABEL(mod_channels_label), temp);
2295 sprintf(temp, "%d", mdi->patterns);
2296 gtk_label_set_text (GTK_LABEL(mod_patterns_label), temp);
2297 sprintf(temp, "%d", mdi->samples);
2298 gtk_label_set_text (GTK_LABEL(mod_samples_label), temp);
2299
2300 vseparator = gtk_vseparator_new ();
2301 gtk_widget_show (vseparator);
2302 gtk_box_pack_start (GTK_BOX (hbox2), vseparator, FALSE, FALSE, 4);
2303
2304 vbox3 = gtk_vbox_new (FALSE, 0);
2305 gtk_widget_show (vbox3);
2306 gtk_box_pack_start (GTK_BOX (hbox2), vbox3, TRUE, TRUE, 0);
2307
2308 scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
2309 gtk_container_set_border_width (GTK_CONTAINER (scrolledwindow), 4);
2310 gtk_widget_show (scrolledwindow);
2311 gtk_widget_set_size_request (scrolledwindow, -1, 220);
2312 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
2313 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2314 gtk_box_pack_end (GTK_BOX (vbox3), scrolledwindow, TRUE, TRUE, 0);
2315 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
2316
2317 fi->smp_instr_list_store = gtk_list_store_new(2,
2318 G_TYPE_STRING,
2319 G_TYPE_STRING);
2320 fi->smp_instr_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(fi->smp_instr_list_store));
2321 gtk_widget_set_name(fi->smp_instr_list, "samples_instruments_list");
2322 gtk_widget_show (fi->smp_instr_list);
2323 renderer = gtk_cell_renderer_text_new();
2324 column = gtk_tree_view_column_new_with_attributes(_("No."), renderer, "text", 0, NULL);
2325 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
2326 GTK_TREE_VIEW_COLUMN_FIXED);
2327 gtk_tree_view_column_set_spacing(GTK_TREE_VIEW_COLUMN(column), 3);
2328 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), FALSE);
2329 gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 40);
2330 gtk_tree_view_append_column(GTK_TREE_VIEW(fi->smp_instr_list), column);
2331 column = gtk_tree_view_column_new_with_attributes(_("Name"), renderer, "text", 1, NULL);
2332 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
2333 GTK_TREE_VIEW_COLUMN_FIXED);
2334 gtk_tree_view_append_column(GTK_TREE_VIEW(fi->smp_instr_list), column);
2335 gtk_tree_view_column_set_spacing(GTK_TREE_VIEW_COLUMN(column), 3);
2336 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), FALSE);
2337 gtk_container_add (GTK_CONTAINER (scrolledwindow), fi->smp_instr_list);
2338
2339 if (mdi->instruments && mdi->type == 0x4) { /* if XM module go to instrument page */
2340 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(instruments_radiobutton), TRUE);
2341 } else {
2342 show_list(fi, 0);
2343 set_first_row(fi);
2344 }
2345 }
2346 #endif /* HAVE_MOD */
2347
2348
2349 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
2350
2351