OSDN Git Service

LinGui: fix a mingw build issue
[handbrake-jp/handbrake-jp-git.git] / gtk / src / presets.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * presets.c
4  * Copyright (C) John Stebbins 2008 <stebbins@stebbins>
5  * 
6  * presets.c is free software.
7  * 
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  * 
13  */
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <unistd.h>
18 #include <glib.h>
19 #include <glib-object.h>
20 #include <glib/gstdio.h>
21 #include <string.h>
22 #include <gtk/gtk.h>
23 #include "hb.h"
24 #include "settings.h"
25 #include "callbacks.h"
26 #include "audiohandler.h"
27 #include "subtitlehandler.h"
28 #include "hb-backend.h"
29 #include "plist.h"
30 #include "resources.h"
31 #include "presets.h"
32 #include "values.h"
33 #include "lang.h"
34
35 #define MAX_NESTED_PRESET 3
36
37 enum
38 {
39         PRESETS_BUILTIN = 0,
40         PRESETS_CUSTOM
41 };
42
43 static GValue *presetsPlist = NULL;
44 static GValue *internalPlist = NULL;
45 static GValue *prefsPlist = NULL;
46 static gboolean prefs_modified = FALSE;
47
48 static const GValue* preset_dict_get_value(GValue *dict, const gchar *key);
49 static void store_plist(GValue *plist, const gchar *name);
50 static void store_presets(void);
51 static void store_prefs(void);
52
53 gint
54 preset_path_cmp(gint *indices1, gint len1, gint *indices2, gint len2)
55 {
56         gint ii;
57         for (ii = 0; ii < len1 && ii < len2; ii++)
58         {
59                 if (indices1[ii] != indices2[ii])
60                         return indices1[ii] - indices2[ii];
61         }
62         return len1 - len2;
63 }
64
65 // This only handle limited depth
66 GtkTreePath*
67 ghb_tree_path_new_from_indices(gint *indices, gint len)
68 {
69         switch (len)
70         {
71                 case 1:
72                         return gtk_tree_path_new_from_indices(
73                                 indices[0], -1);
74                 case 2:
75                         return gtk_tree_path_new_from_indices(
76                                 indices[0], indices[1], -1);
77                 case 3:
78                         return gtk_tree_path_new_from_indices(
79                                 indices[0], indices[1], indices[2], -1);
80                 case 4:
81                         return gtk_tree_path_new_from_indices(
82                                 indices[0], indices[1], indices[2], indices[3], -1);
83                 case 5:
84                         return gtk_tree_path_new_from_indices(
85                                 indices[0], indices[1], indices[2], indices[3], indices[4], -1);
86                 default:
87                         return NULL;
88         }
89 }
90
91 GValue*
92 ghb_parse_preset_path(const gchar *path)
93 {
94         gchar **split;
95         GValue *preset;
96         gint ii;
97
98         preset = ghb_array_value_new(MAX_NESTED_PRESET);
99         split = g_strsplit(path, "#", MAX_NESTED_PRESET);
100         for (ii = 0; split[ii] != NULL; ii++)
101         {
102                 ghb_array_append(preset, ghb_string_value_new(split[ii]));
103         }
104         g_strfreev(split);
105         return preset;
106 }
107
108 static GValue*
109 preset_path_from_indices(GValue *presets, gint *indices, gint len)
110 {
111         gint ii;
112         GValue *path;
113
114         g_debug("preset_path_from_indices");
115         path = ghb_array_value_new(MAX_NESTED_PRESET);
116         for (ii = 0; ii < len; ii++)
117         {
118                 GValue *dict;
119                 gint count, folder;
120                 const GValue *name;
121
122                 count = ghb_array_len(presets);
123                 if (indices[ii] >= count) break;
124                 dict = ghb_array_get_nth(presets, indices[ii]);
125                 name = ghb_dict_lookup(dict, "PresetName");
126                 if (name)
127                         ghb_array_append(path, ghb_value_dup(name));
128                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
129                 if (!folder)
130                         break;
131                 presets = ghb_dict_lookup(dict, "ChildrenArray");
132         }
133         return path;
134 }
135
136 gchar*
137 ghb_preset_path_string(const GValue *path)
138 {
139         gint count, ii;
140         GString *gstr;
141         GValue *val;
142         gchar *str;
143
144         gstr = g_string_new("");
145         if (path != NULL)
146         {
147                 count = ghb_array_len(path);
148                 for (ii = 0; ii < count; ii++)
149                 {
150                         val = ghb_array_get_nth(path, ii);
151                         str = ghb_value_string(val);
152                         g_string_append(gstr, str);
153                         if (ii < count-1)
154                                 g_string_append(gstr, "->");
155                         g_free(str);
156                 }
157         }
158         str = g_string_free(gstr, FALSE);
159         return str;
160 }
161
162 void
163 dump_preset_path(const gchar *msg, const GValue *path)
164 {
165         gchar *str;
166
167         if (path)
168                 debug_show_type (G_VALUE_TYPE(path));
169         str = ghb_preset_path_string(path);
170         g_message("%s path: (%s)", msg, str);
171         g_free(str);
172 }
173
174 void
175 dump_preset_indices(const gchar *msg, gint *indices, gint len)
176 {
177         gint ii;
178
179         g_message("%s indices: len %d", msg, len);
180         for (ii = 0; ii < len; ii++)
181         {
182                 printf("%d ", indices[ii]);
183         }
184         printf("\n");
185 }
186
187 #if 0
188 static gint
189 preset_path_cmp(const GValue *path1, const GValue *path2)
190 {
191         gint count, ii;
192         GValue *val;
193         gchar *str1, *str2;
194         gint result;
195
196         count = ghb_array_len(path1);
197         ii = ghb_array_len(path2);
198         if (ii != count)
199                 return ii - count;
200         for (ii = 0; ii < count; ii++)
201         {
202                 val = ghb_array_get_nth(path1, ii);
203                 str1 = ghb_value_string(val);
204                 val = ghb_array_get_nth(path2, ii);
205                 str2 = ghb_value_string(val);
206                 result = strcmp(str1, str2);
207                 if (result != 0)
208                         return result;
209                 g_free(str1);
210                 g_free(str2);
211         }
212         return 0;
213 }
214 #endif
215
216 static GValue*
217 presets_get_dict(GValue *presets, gint *indices, gint len)
218 {
219         gint ii, count, folder;
220         GValue *dict = NULL;
221
222         g_debug("presets_get_dict ()");
223         for (ii = 0; ii < len; ii++)
224         {
225                 count = ghb_array_len(presets);
226                 if (indices[ii] >= count) return NULL;
227                 dict = ghb_array_get_nth(presets, indices[ii]);
228                 if (ii < len-1)
229                 {
230                         folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
231                         if (!folder)
232                                 return NULL;
233                         presets = ghb_dict_lookup(dict, "ChildrenArray");
234                 }
235         }
236         if (ii < len)
237                 return NULL;
238         return dict;
239 }
240
241 static GValue*
242 presets_get_folder(GValue *presets, gint *indices, gint len)
243 {
244         gint ii, count, folder;
245         GValue *dict;
246
247         g_debug("presets_get_folder ()");
248         for (ii = 0; ii < len; ii++)
249         {
250                 count = ghb_array_len(presets);
251                 if (indices[ii] >= count) return NULL;
252                 dict = ghb_array_get_nth(presets, indices[ii]);
253                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
254                 if (!folder)
255                         break;
256                 presets = ghb_dict_lookup(dict, "ChildrenArray");
257         }
258         if (ii < len)
259                 return NULL;
260         return presets;
261 }
262
263 static GValue*
264 plist_get_dict(GValue *presets, const gchar *name)
265 {
266         if (presets == NULL || name == NULL) return NULL;
267         return ghb_dict_lookup(presets, name);
268 }
269
270 static const gchar*
271 preset_get_name(GValue *dict)
272 {
273         return g_value_get_string(preset_dict_get_value(dict, "PresetName"));
274 }
275
276 static gboolean
277 preset_folder_is_open(GValue *dict)
278 {
279         const GValue *gval;
280
281         gval = preset_dict_get_value(dict, "FolderOpen");
282         if (gval != NULL)
283                 return g_value_get_boolean(gval);
284         return FALSE;
285 }
286
287 gboolean
288 ghb_preset_folder(GValue *dict)
289 {
290         return ghb_value_int(preset_dict_get_value(dict, "Folder"));
291 }
292
293 gint
294 ghb_preset_type(GValue *dict)
295 {
296         return ghb_value_int(preset_dict_get_value(dict, "Type"));
297 }
298
299 static void
300 presets_remove_nth(GValue *presets, gint pos)
301 {
302         GValue *dict;
303         gint count;
304         
305         if (presets == NULL || pos < 0) return;
306         count = ghb_array_len(presets);
307         if (pos >= count) return;
308         dict = ghb_array_get_nth(presets, pos);
309         ghb_array_remove(presets, pos);
310         ghb_value_free(dict);
311 }
312
313 gboolean
314 ghb_presets_remove(
315         GValue *presets, 
316         gint *indices,
317         gint len)
318 {
319         GValue *folder = NULL;
320
321         folder = presets_get_folder(presets, indices, len-1);
322         if (folder)
323                 presets_remove_nth(folder, indices[len-1]);
324         else
325         {
326                 g_warning("ghb_presets_remove (): internal preset lookup error");
327                 return FALSE;
328         }
329         return TRUE;
330 }
331
332 static void
333 ghb_presets_replace(
334         GValue *presets, 
335         GValue *dict,
336         gint *indices,
337         gint len)
338 {
339         GValue *folder = NULL;
340
341         folder = presets_get_folder(presets, indices, len-1);
342         if (folder)
343                 ghb_array_replace(folder, indices[len-1], dict);
344         else
345         {
346                 g_warning("ghb_presets_replace (): internal preset lookup error");
347         }
348 }
349
350 static void
351 ghb_presets_insert(
352         GValue *presets, 
353         GValue *dict,
354         gint *indices,
355         gint len)
356 {
357         GValue *folder = NULL;
358
359         folder = presets_get_folder(presets, indices, len-1);
360         if (folder)
361                 ghb_array_insert(folder, indices[len-1], dict);
362         else
363         {
364                 g_warning("ghb_presets_insert (): internal preset lookup error");
365         }
366 }
367
368 static gint
369 presets_find_element(GValue *presets, const gchar *name)
370 {
371         GValue *dict;
372         gint count, ii;
373         
374         g_debug("presets_find_element () (%s)", name);
375         if (presets == NULL || name == NULL) return -1;
376         count = ghb_array_len(presets);
377         for (ii = 0; ii < count; ii++)
378         {
379                 const gchar *str;
380                 dict = ghb_array_get_nth(presets, ii);
381                 str = preset_get_name(dict);
382                 if (strcmp(name, str) == 0)
383                 {
384                         return ii;
385                 }
386         }
387         return -1;
388 }
389
390 static gint
391 single_find_pos(GValue *presets, const gchar *name, gint type)
392 {
393         GValue *dict;
394         gint count, ii, ptype, last;
395         
396         if (presets == NULL || name == NULL) return -1;
397         last = count = ghb_array_len(presets);
398         for (ii = 0; ii < count; ii++)
399         {
400                 const gchar *str;
401                 dict = ghb_array_get_nth(presets, ii);
402                 str = preset_get_name(dict);
403                 ptype = ghb_value_int(preset_dict_get_value(dict, "Type"));
404                 if (strcasecmp(name, str) <= 0 && ptype == type)
405                 {
406                         return ii;
407                 }
408                 if (ptype == type)
409                         last = ii+1;
410         }
411         return last;
412 }
413
414 static gint*
415 presets_find_pos(const GValue *path, gint type, gint *len)
416 {
417         GValue *nested;
418         GValue *val;
419         gint count, ii;
420         gboolean folder;
421         gint *indices = NULL;
422         const gchar *name;
423         GValue *dict;
424
425         g_debug("presets_find_pos () ");
426         nested = presetsPlist;
427         count = ghb_array_len(path);
428         indices = g_malloc(MAX_NESTED_PRESET * sizeof(gint));
429         for (ii = 0; ii < count-1; ii++)
430         {
431                 val = ghb_array_get_nth(path, ii);
432                 name = g_value_get_string(val);
433                 indices[ii] = presets_find_element(nested, name);
434                 if (indices[ii] == -1) return NULL;
435                 dict = ghb_array_get_nth(nested, indices[ii]);
436                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
437                 nested = NULL;
438                 if (!folder)
439                         break;
440                 nested = ghb_dict_lookup(dict, "ChildrenArray");
441         }
442         if (nested)
443         {
444                 const gchar *name;
445
446                 name = g_value_get_string(ghb_array_get_nth(path, count-1));
447                 indices[ii] = single_find_pos(nested, name, type);
448                 ii++;
449         }
450         *len = ii;
451         return indices;
452 }
453
454 static gint
455 preset_tree_depth(GValue *dict)
456 {
457         gboolean folder;
458
459         folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
460         if (folder)
461         {
462                 gint depth = 0;
463                 gint count, ii;
464                 GValue *presets;
465
466                 presets = ghb_dict_lookup(dict, "ChildrenArray");
467                 count = ghb_array_len(presets);
468                 for (ii = 0; ii < count; ii++)
469                 {
470                         gint tmp;
471
472                         dict = ghb_array_get_nth(presets, ii);
473                         tmp = preset_tree_depth(dict);
474                         depth = MAX(depth, tmp);
475                 }
476                 return depth + 1;
477         }
478         else
479         {
480                 return 1;
481         }
482 }
483
484 static gboolean
485 preset_is_default(GValue *dict)
486 {
487         const GValue *val;
488
489         val = preset_dict_get_value(dict, "Default");
490         return ghb_value_boolean(val);
491 }
492
493 static void
494 presets_clear_default(GValue *presets)
495 {
496         gint count, ii;
497
498         count = ghb_array_len(presets);
499         for (ii = 0; ii < count; ii++)
500         {
501                 GValue *dict;
502                 gboolean folder;
503
504                 dict = ghb_array_get_nth(presets, ii);
505                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
506                 if (folder)
507                 {
508                         GValue *nested;
509
510                         nested = ghb_dict_lookup(dict, "ChildrenArray");
511                         presets_clear_default(nested);
512                 }
513                 else
514                 {
515                         if (preset_is_default(dict))
516                         {
517                                 ghb_dict_insert(dict, g_strdup("Default"), 
518                                                                 ghb_boolean_value_new(FALSE));
519                         }
520                 }
521         }
522 }
523
524 static void
525 presets_customize(GValue *presets)
526 {
527         gint count, ii;
528
529         count = ghb_array_len(presets);
530         for (ii = 0; ii < count; ii++)
531         {
532                 GValue *dict;
533                 gboolean folder;
534                 gint ptype;
535
536                 dict = ghb_array_get_nth(presets, ii);
537
538                 ptype = ghb_value_int(preset_dict_get_value(dict, "Type"));
539                 if (ptype != PRESETS_CUSTOM)
540                 {
541                         ghb_dict_insert(dict, g_strdup("Type"), 
542                                                 ghb_int64_value_new(PRESETS_CUSTOM));
543                 }
544                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
545                 if (folder)
546                 {
547                         GValue *nested;
548
549                         nested = ghb_dict_lookup(dict, "ChildrenArray");
550                         presets_customize(nested);
551                 }
552         }
553 }
554
555 static gint*
556 presets_find_default2(GValue *presets, gint *len)
557 {
558         gint count, ii;
559         gint *indices;
560
561         count = ghb_array_len(presets);
562         for (ii = 0; ii < count; ii++)
563         {
564                 GValue *dict;
565                 gboolean folder;
566
567                 dict = ghb_array_get_nth(presets, ii);
568                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
569                 if (folder)
570                 {
571                         GValue *nested;
572                         gint pos = *len;
573
574                         nested = ghb_dict_lookup(dict, "ChildrenArray");
575                         (*len)++;
576                         indices = presets_find_default2(nested, len);
577                         if (indices)
578                         {
579                                 indices[pos] = ii;
580                                 return indices;
581                         }
582                         else
583                                 *len = pos;
584                 }
585                 else
586                 {
587                         if (preset_is_default(dict))
588                         {
589                                 indices = g_malloc(MAX_NESTED_PRESET * sizeof(gint));
590                                 indices[*len] = ii;
591                                 (*len)++;
592                                 return indices;
593                         }
594                 }
595         }
596         return NULL;
597 }
598
599 static gint*
600 presets_find_default(GValue *presets, gint *len)
601 {
602         *len = 0;
603         return presets_find_default2(presets, len);
604 }
605
606 gint*
607 ghb_preset_indices_from_path(
608         GValue *presets, 
609         const GValue *path,
610         gint *len)
611 {
612         GValue *nested;
613         GValue *val;
614         gint count, ii;
615         gint *indices = NULL;
616         const gchar *name;
617         GValue *dict;
618         gboolean folder;
619
620         g_debug("ghb_preset_indices_from_path () ");
621         nested = presets;
622         count = ghb_array_len(path);
623         if (count)
624                 indices = g_malloc(MAX_NESTED_PRESET * sizeof(gint));
625         *len = 0;
626         for (ii = 0; ii < count; ii++)
627         {
628                 val = ghb_array_get_nth(path, ii);
629                 name = g_value_get_string(val);
630                 indices[ii] = presets_find_element(nested, name);
631                 if (indices[ii] == -1)
632                 {
633                         g_free(indices);
634                         return NULL;
635                 }
636                 if (ii < count-1)
637                 {
638                         dict = ghb_array_get_nth(nested, indices[ii]);
639                         folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
640                         if (!folder)
641                         {
642                                 g_free(indices);
643                                 return NULL;
644                         }
645                         nested = ghb_dict_lookup(dict, "ChildrenArray");
646                 }
647         }
648         *len = ii;
649         return indices;
650 }
651
652 static gint
653 ghb_presets_get_type(
654         GValue *presets, 
655         gint *indices,
656         gint len)
657 {
658         GValue *dict;
659         gint type = 0;
660
661         dict = presets_get_dict(presets, indices, len);
662         if (dict)
663         {
664                 type = ghb_preset_type(dict);
665         }
666         else
667         {
668                 g_warning("ghb_presets_get_type (): internal preset lookup error");
669         }
670         return type;
671 }
672
673 static gboolean
674 ghb_presets_get_folder(
675         GValue *presets, 
676         gint *indices,
677         gint len)
678 {
679         GValue *dict;
680         gboolean folder = FALSE;
681
682         dict = presets_get_dict(presets, indices, len);
683         if (dict)
684         {
685                 folder = ghb_preset_folder(dict);
686         }
687         else
688         {
689                 g_warning("ghb_presets_get_folder (): internal preset lookup error");
690         }
691         return folder;
692 }
693
694 void
695 presets_set_default(gint *indices, gint len)
696 {
697         GValue *dict;
698         
699         g_debug("presets_set_default ()");
700         presets_clear_default(presetsPlist);
701         dict = presets_get_dict(presetsPlist, indices, len);
702         if (dict)
703         {
704                 ghb_dict_insert(dict, g_strdup("Default"), ghb_boolean_value_new(TRUE));
705         }
706         store_presets();
707 }
708
709 static void
710 presets_set_folder_open(gboolean open, gint *indices, gint len)
711 {
712         GValue *dict;
713         
714         g_debug("presets_set_folder_open ()");
715         dict = presets_get_dict(presetsPlist, indices, len);
716         if (dict)
717         {
718                 ghb_dict_insert(dict, g_strdup("FolderOpen"), 
719                                                 ghb_boolean_value_new(open));
720         }
721 }
722
723 // Used for sorting dictionaries.
724 gint
725 key_cmp(gconstpointer a, gconstpointer b)
726 {
727         gchar *stra = (gchar*)a;
728         gchar *strb = (gchar*)b;
729
730         return strcmp(stra, strb);
731 }
732
733 static const GValue*
734 preset_dict_get_value(GValue *dict, const gchar *key)
735 {
736         const GValue *gval = NULL;
737
738         if (dict)
739         {
740                 gval = ghb_dict_lookup(dict, key);
741         }
742         if (internalPlist == NULL) return NULL;
743         if (gval == NULL)
744         {
745                 dict = plist_get_dict(internalPlist, "Presets");
746                 if (dict == NULL) return NULL;
747                 gval = ghb_dict_lookup(dict, key);
748         }
749         return gval;
750 }
751
752 const gchar*
753 ghb_presets_get_description(GValue *pdict)
754 {
755         const gchar *desc;
756
757         if (pdict == NULL) return NULL;
758         desc = g_value_get_string(
759                         preset_dict_get_value(pdict, "PresetDescription"));
760         if (desc[0] == 0) return NULL;
761         return desc;
762 }
763
764
765 static void init_settings_from_dict(
766         GValue *dest, GValue *internal, GValue *dict);
767
768 static void
769 init_settings_from_array(
770         GValue *dest, 
771         GValue *internal,
772         GValue *array)
773 {
774         GValue *gval, *val;
775         gint count, ii;
776         
777         count = ghb_array_len(array);
778         // The first element of the internal version is always the 
779         // template for the allowed values
780         gval = ghb_array_get_nth(internal, 0);
781         for (ii = 0; ii < count; ii++)
782         {
783                 val = NULL;
784                 val = ghb_array_get_nth(array, ii);
785                 if (val == NULL)
786                         val = gval;
787                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
788                 {
789                         GValue *new_dict;
790                         new_dict = ghb_dict_value_new();
791                         ghb_array_append(dest, new_dict);
792                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
793                                 init_settings_from_dict(new_dict, gval, val);
794                         else
795                                 init_settings_from_dict(new_dict, gval, gval);
796                 }
797                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
798                 {
799                         GValue *new_array;
800                         new_array = ghb_array_value_new(8);
801                         ghb_array_append(dest, new_array);
802                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
803                                 init_settings_from_array(new_array, gval, val);
804                         else
805                                 init_settings_from_array(new_array, gval, gval);
806                 }
807                 else
808                 {
809                         ghb_array_append(dest, val);
810                 }
811         }
812 }
813
814 static void
815 init_settings_from_dict(
816         GValue *dest, 
817         GValue *internal,
818         GValue *dict)
819 {
820         GHashTableIter iter;
821         gchar *key;
822         GValue *gval, *val;
823         
824         ghb_dict_iter_init(&iter, internal);
825         // middle (void*) cast prevents gcc warning "defreferencing type-punned
826         // pointer will break strict-aliasing rules"
827         while (g_hash_table_iter_next(
828                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
829         {
830                 val = NULL;
831                 if (dict)
832                         val = ghb_dict_lookup(dict, key);
833                 if (val == NULL)
834                         val = gval;
835                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
836                 {
837                         GValue *new_dict;
838                         new_dict = ghb_dict_value_new();
839                         ghb_settings_take_value(dest, key, new_dict);
840                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
841                                 init_settings_from_dict(new_dict, gval, val);
842                         else
843                                 init_settings_from_dict(new_dict, gval, gval);
844                 }
845                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
846                 {
847                         GValue *new_array;
848                         new_array = ghb_array_value_new(8);
849                         ghb_settings_take_value(dest, key, new_array);
850                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
851                                 init_settings_from_array(new_array, gval, val);
852                         else
853                                 init_settings_from_array(new_array, gval, gval);
854         
855                 }
856                 else
857                 {
858                         ghb_settings_set_value(dest, key, val);
859                 }
860         }
861 }
862
863 void
864 init_ui_from_dict(
865         signal_user_data_t *ud, 
866         GValue *internal,
867         GValue *dict)
868 {
869         GHashTableIter iter;
870         gchar *key;
871         GValue *gval, *val;
872         
873         ghb_dict_iter_init(&iter, internal);
874         // middle (void*) cast prevents gcc warning "defreferencing type-punned
875         // pointer will break strict-aliasing rules"
876         while (g_hash_table_iter_next(
877                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
878         {
879                 val = NULL;
880                 if (dict)
881                         val = ghb_dict_lookup(dict, key);
882                 if (val == NULL)
883                         val = gval;
884                 ghb_ui_update(ud, key, val);
885         }
886 }
887
888 static void
889 preset_to_ui(signal_user_data_t *ud, GValue *dict)
890 {
891         g_debug("preset_to_ui()\n");
892         // Initialize the ui from presets file.
893         GValue *internal, *hidden;
894
895         // Get key list from internal default presets.  This way we do not
896         // load any unknown keys.
897         if (internalPlist == NULL) return;
898         internal = plist_get_dict(internalPlist, "Presets");
899         hidden = plist_get_dict(internalPlist, "XlatPresets");
900         // Setting a ui widget will cause the corresponding setting
901         // to be set, but it also triggers a callback that can 
902         // have the side effect of using other settings values
903         // that have not yet been set.  So set *all* settings first
904         // then update the ui.
905         init_settings_from_dict(ud->settings, internal, dict);
906         init_settings_from_dict(ud->settings, hidden, dict);
907         init_ui_from_dict(ud, internal, dict);
908         init_ui_from_dict(ud, hidden, dict);
909
910         if (dict != NULL)
911         {
912                 GValue *val;
913                 gboolean dd;
914
915                 val = ghb_dict_lookup(dict, "PictureDecombDeinterlace");
916                 if (val != NULL)
917                 {
918                         dd = ghb_value_boolean(val);
919                         ghb_ui_update(ud, "PictureDeinterlaceDecomb", ghb_boolean_value(!dd));
920                 }
921         }
922 }
923
924 void
925 ghb_settings_to_ui(signal_user_data_t *ud, GValue *dict)
926 {
927         init_ui_from_dict(ud, dict, dict);
928 }
929
930 static GValue *current_preset = NULL;
931
932 gboolean
933 ghb_preset_is_custom()
934 {
935         const GValue *val;
936
937         if (current_preset == NULL) return FALSE;
938         val = preset_dict_get_value(current_preset, "Type");
939         return (ghb_value_int(val) == 1);
940 }
941
942 void
943 ghb_set_preset_from_indices(signal_user_data_t *ud, gint *indices, gint len)
944 {
945         GValue *dict = NULL;
946         gint fallback[2] = {0, -1};
947
948         if (indices)
949                 dict = presets_get_dict(presetsPlist, indices, len);
950         if (dict == NULL)
951         {
952                 indices = fallback;
953                 len = 1;
954                 dict = presets_get_dict(presetsPlist, indices, len);
955         }
956         if (dict == NULL)
957         {
958                 preset_to_ui(ud, NULL);
959                 current_preset = NULL;
960         }
961         else
962         {
963                 GValue *path;
964                 gboolean folder;
965
966                 current_preset = dict;
967                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
968                 if (folder)
969                         preset_to_ui(ud, NULL);
970                 else
971                         preset_to_ui(ud, dict);
972                 path = preset_path_from_indices(presetsPlist, indices, len);
973                 ghb_settings_set_value(ud->settings, "preset", path);
974                 ghb_value_free(path);
975         }
976 }
977
978 static const GValue*
979 curr_preset_get_value(const gchar *key)
980 {
981         if (current_preset == NULL) return NULL;
982         return preset_dict_get_value(current_preset, key);
983 }
984
985 void
986 ghb_update_from_preset(
987         signal_user_data_t *ud, 
988         const gchar *key)
989 {
990         const GValue *gval;
991         
992         g_debug("ghb_update_from_preset() %s", key);
993         gval = curr_preset_get_value(key);
994         if (gval != NULL)
995         {
996                 ghb_ui_update(ud, key, gval);
997         }
998 }
999
1000 static void
1001 ghb_select_preset2(
1002         GtkBuilder *builder, 
1003         gint *indices, 
1004         gint len)
1005 {
1006         GtkTreeView *treeview;
1007         GtkTreeSelection *selection;
1008         GtkTreeModel *store;
1009         GtkTreeIter iter;
1010         GtkTreePath *path;
1011         
1012         g_debug("ghb_select_preset2()");
1013         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
1014         selection = gtk_tree_view_get_selection (treeview);
1015         store = gtk_tree_view_get_model (treeview);
1016         path = ghb_tree_path_new_from_indices(indices, len);
1017         if (path)
1018         {
1019                 if (gtk_tree_model_get_iter(store, &iter, path))
1020                 {
1021                         gtk_tree_selection_select_iter (selection, &iter);
1022                 }
1023                 else
1024                 {
1025                         if (gtk_tree_model_get_iter_first(store, &iter))
1026                                 gtk_tree_selection_select_iter (selection, &iter);
1027                 }
1028                 gtk_tree_path_free(path);
1029         }
1030 }
1031
1032 void
1033 ghb_select_preset(GtkBuilder *builder, const GValue *path)
1034 {
1035         gint *indices, len;
1036
1037         g_debug("ghb_select_preset()");
1038         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
1039         if (indices)
1040         {
1041                 ghb_select_preset2(builder, indices, len);
1042                 g_free(indices);
1043         }
1044 }
1045
1046 void
1047 ghb_select_default_preset(GtkBuilder *builder)
1048 {
1049         gint *indices, len;
1050
1051         g_debug("ghb_select_default_preset()");
1052         indices = presets_find_default(presetsPlist, &len);
1053         if (indices)
1054         {
1055                 ghb_select_preset2(builder, indices, len);
1056                 g_free(indices);
1057         }
1058 }
1059
1060 gchar*
1061 ghb_get_user_config_dir(gchar *subdir)
1062 {
1063         const gchar *dir;
1064         gchar *config;
1065
1066         dir = g_get_user_config_dir();
1067         if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
1068         {
1069                 dir = g_get_home_dir();
1070                 config = g_strdup_printf ("%s/.ghb", dir);
1071                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
1072                         g_mkdir (config, 0755);
1073         }
1074         else
1075         {
1076                 config = g_strdup_printf ("%s/ghb", dir);
1077                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
1078                         g_mkdir (config, 0755);
1079         }
1080         if (subdir)
1081         {
1082                 gchar **split;
1083                 gint ii;
1084
1085                 split = g_strsplit(subdir, G_DIR_SEPARATOR_S, -1);
1086                 for (ii = 0; split[ii] != NULL; ii++)
1087                 {
1088                         gchar *tmp;
1089
1090                         tmp = g_strdup_printf ("%s/%s", config, split[ii]);
1091                         g_free(config);
1092                         config = tmp;
1093                         if (!g_file_test(config, G_FILE_TEST_IS_DIR))
1094                                 g_mkdir (config, 0755);
1095                 }
1096         }
1097         return config;
1098 }
1099
1100 static void
1101 store_plist(GValue *plist, const gchar *name)
1102 {
1103         gchar *config, *path;
1104         FILE *file;
1105
1106         config = ghb_get_user_config_dir(NULL);
1107         path = g_strdup_printf ("%s/%s", config, name);
1108         file = g_fopen(path, "w");
1109         g_free(config);
1110         g_free(path);
1111         ghb_plist_write(file, plist);
1112         fclose(file);
1113 }
1114
1115 static GValue*
1116 load_plist(const gchar *name)
1117 {
1118         gchar *config, *path;
1119         GValue *plist = NULL;
1120
1121         config = ghb_get_user_config_dir(NULL);
1122         path = g_strdup_printf ("%s/%s", config, name);
1123         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
1124         {
1125                 plist = ghb_plist_parse_file(path);
1126         }
1127         g_free(config);
1128         g_free(path);
1129         return plist;
1130 }
1131
1132 gboolean
1133 ghb_lock_file(const gchar *name)
1134 {
1135 #if !defined(_WIN32)
1136         gchar *config, *path;
1137         int fd, lock = 0;
1138
1139         config = ghb_get_user_config_dir(NULL);
1140         path = g_strdup_printf ("%s/%s", config, name);
1141         fd = open(path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
1142         if (fd >= 0)
1143                 lock = lockf(fd, F_TLOCK, 0);
1144         if (lock)
1145                 close(fd);
1146         g_free(config);
1147         g_free(path);
1148         return !lock;
1149 #else
1150         return 1;
1151 #endif
1152 }
1153
1154 void
1155 ghb_write_pid_file()
1156 {
1157 #if !defined(_WIN32)
1158         gchar *config, *path;
1159         pid_t pid;
1160         FILE *fp;
1161         int fd, lock;
1162
1163         pid = getpid();
1164
1165         config = ghb_get_user_config_dir(NULL);
1166         path = g_strdup_printf ("%s/ghb.pid.%d", config, pid);
1167
1168         fp = g_fopen(path, "w");
1169         fprintf(fp, "%d\n", pid);
1170         fclose(fp);
1171
1172         fd = open(path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
1173         lock = lockf(fd, F_TLOCK, 0);
1174
1175         g_free(config);
1176         g_free(path);
1177 #endif
1178 }
1179
1180 void
1181 ghb_unlink_pid_file(int pid)
1182 {
1183         gchar *config, *path;
1184
1185         config = ghb_get_user_config_dir(NULL);
1186         path = g_strdup_printf ("%s/ghb.pid.%d", config, pid);
1187
1188         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
1189         {
1190                 g_unlink(path);
1191         }
1192
1193         g_free(config);
1194         g_free(path);
1195 }
1196
1197 int
1198 ghb_find_pid_file()
1199 {
1200         const gchar *file;
1201         gchar *config;
1202
1203         config = ghb_get_user_config_dir(NULL);
1204
1205         if (g_file_test(config, G_FILE_TEST_IS_DIR))
1206         {
1207                 GDir *gdir = g_dir_open(config, 0, NULL);
1208                 file = g_dir_read_name(gdir);
1209                 while (file)
1210                 {
1211                         if (strncmp(file, "ghb.pid.", 8) == 0)
1212                         {
1213                                 gchar *path;
1214                                 pid_t my_pid;
1215                                 int pid;
1216
1217                                 sscanf(file, "ghb.pid.%d", &pid);
1218                                 my_pid = getpid();
1219                                 if (my_pid == pid)
1220                                 {
1221                                         file = g_dir_read_name(gdir);
1222                                         continue;
1223                                 }
1224                                 path = g_strdup_printf("%s/%s", config, file);
1225
1226 #if !defined(_WIN32)
1227                                 int fd, lock = 1;
1228
1229                                 fd = open(path, O_RDWR);
1230                                 if (fd >= 0)
1231                                 {
1232                                         lock = lockf(fd, F_TLOCK, 0);
1233                                 }
1234                                 if (lock == 0)
1235                                 {
1236                                         close(fd);
1237                                         g_dir_close(gdir);
1238                                         g_unlink(path);
1239                                         g_free(path);
1240                                         g_free(config);
1241                                         return pid;
1242                                 }
1243                                 g_free(path);
1244                                 close(fd);
1245 #else
1246                                 g_dir_close(gdir);
1247                                 g_unlink(path);
1248                                 g_free(path);
1249                                 g_free(config);
1250                                 return pid;
1251 #endif
1252                         }
1253                         file = g_dir_read_name(gdir);
1254                 }
1255                 g_dir_close(gdir);
1256         }
1257         g_free(config);
1258         return -1;
1259 }
1260
1261 static void
1262 remove_plist(const gchar *name)
1263 {
1264         gchar *config, *path;
1265
1266         config = ghb_get_user_config_dir(NULL);
1267         path = g_strdup_printf ("%s/%s", config, name);
1268         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
1269         {
1270                 g_unlink(path);
1271         }
1272         g_free(path);
1273         g_free(config);
1274 }
1275
1276 static gboolean prefs_initializing = FALSE;
1277
1278 void
1279 ghb_prefs_to_ui(signal_user_data_t *ud)
1280 {
1281         const GValue *gval;
1282         gchar *key;
1283         gchar *str;
1284         GValue *internal, *dict;
1285         GHashTableIter iter;
1286         
1287
1288         g_debug("ghb_prefs_to_ui");
1289         prefs_initializing = TRUE;
1290
1291         // Setting a ui widget will cause the corresponding setting
1292         // to be set, but it also triggers a callback that can 
1293         // have the side effect of using other settings values
1294         // that have not yet been set.  So set *all* settings first
1295         // then update the ui.
1296         internal = plist_get_dict(internalPlist, "Initialization");
1297         ghb_dict_iter_init(&iter, internal);
1298         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1299         // pointer will break strict-aliasing rules"
1300         while (g_hash_table_iter_next(
1301                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1302         {
1303                 ghb_ui_update(ud, key, gval);
1304         }
1305
1306         dict = plist_get_dict(prefsPlist, "Preferences");
1307         internal = plist_get_dict(internalPlist, "Preferences");
1308         ghb_dict_iter_init(&iter, internal);
1309         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1310         // pointer will break strict-aliasing rules"
1311         while (g_hash_table_iter_next(
1312                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1313         {
1314                 const GValue *value = NULL;
1315                 if (dict)
1316                         value = ghb_dict_lookup(dict, key);
1317                 if (value == NULL)
1318                         value = gval;
1319                 ghb_settings_set_value(ud->settings, key, value);
1320         }
1321         internal = plist_get_dict(internalPlist, "Preferences");
1322         ghb_dict_iter_init(&iter, internal);
1323         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1324         // pointer will break strict-aliasing rules"
1325         while (g_hash_table_iter_next(
1326                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1327         {
1328                 const GValue *value = NULL;
1329                 if (dict)
1330                         value = ghb_dict_lookup(dict, key);
1331                 if (value == NULL)
1332                         value = gval;
1333                 ghb_ui_update(ud, key, value);
1334         }
1335         const GValue *val;
1336         val = ghb_settings_get_value(ud->settings, "show_presets");
1337         ghb_ui_update(ud, "show_presets", val);
1338         if (ghb_settings_get_boolean(ud->settings, "hbfd_feature"))
1339         {
1340                 GtkAction *action;
1341                 val = ghb_settings_get_value(ud->settings, "hbfd");
1342                 ghb_ui_update(ud, "hbfd", val);
1343                 action = GHB_ACTION (ud->builder, "hbfd");
1344                 gtk_action_set_visible(action, TRUE);
1345         }
1346         else
1347         {
1348                 ghb_ui_update(ud, "hbfd", ghb_int64_value(0));
1349         }
1350         gval = ghb_settings_get_value(ud->settings, "default_source");
1351         ghb_settings_set_value (ud->settings, "scan_source", gval);
1352
1353         str = ghb_settings_get_string(ud->settings, "destination_dir");
1354         ghb_ui_update(ud, "dest_dir", ghb_string_value(str));
1355
1356         gchar *file = g_strdup_printf ("new_video.mp4");
1357         ghb_ui_update(ud, "dest_file", ghb_string_value(file));
1358         g_free(str);
1359         g_free(file);
1360
1361         prefs_initializing = FALSE;
1362 }
1363
1364 void
1365 ghb_prefs_save(GValue *settings)
1366 {
1367         GValue *dict;
1368         GValue *pref_dict;
1369         GHashTableIter iter;
1370         gchar *key;
1371         const GValue *value;
1372         
1373         if (prefs_initializing) return;
1374         dict = plist_get_dict(internalPlist, "Preferences");
1375         if (dict == NULL) return;
1376         pref_dict = plist_get_dict(prefsPlist, "Preferences");
1377         if (pref_dict == NULL) return;
1378         ghb_dict_iter_init(&iter, dict);
1379         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1380         // pointer will break strict-aliasing rules"
1381         while (g_hash_table_iter_next(
1382                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
1383         {
1384                 value = ghb_settings_get_value(settings, key);
1385                 if (value != NULL)
1386                 {
1387                         ghb_dict_insert(pref_dict, g_strdup(key), ghb_value_dup(value));
1388                 }
1389         }
1390         store_prefs();
1391         prefs_modified = FALSE;
1392 }
1393
1394 void
1395 ghb_pref_set(GValue *settings, const gchar *key)
1396 {
1397         const GValue *value, *value2;
1398         
1399         if (prefs_initializing) return;
1400         value = ghb_settings_get_value(settings, key);
1401         if (value != NULL)
1402         {
1403                 GValue *dict;
1404                 dict = plist_get_dict(prefsPlist, "Preferences");
1405                 if (dict == NULL) return;
1406                 value2 = ghb_dict_lookup(dict, key);
1407                 if (ghb_value_cmp(value, value2) != 0)
1408                 {
1409                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
1410                         store_prefs();
1411                         prefs_modified = TRUE;
1412                 }
1413         }
1414 }
1415
1416 void
1417 ghb_pref_save(GValue *settings, const gchar *key)
1418 {
1419         const GValue *value, *value2;
1420         
1421         if (prefs_initializing) return;
1422         value = ghb_settings_get_value(settings, key);
1423         if (value != NULL)
1424         {
1425                 GValue *dict;
1426                 dict = plist_get_dict(prefsPlist, "Preferences");
1427                 if (dict == NULL) return;
1428                 value2 = ghb_dict_lookup(dict, key);
1429                 if (ghb_value_cmp(value, value2) != 0)
1430                 {
1431                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
1432                         store_prefs();
1433                         prefs_modified = FALSE;
1434                 }
1435         }
1436 }
1437
1438 void
1439 ghb_prefs_store(void)
1440 {
1441         if (prefs_modified)
1442         {
1443                 store_prefs();
1444                 prefs_modified = FALSE;
1445         }
1446 }
1447
1448 void
1449 ghb_settings_init(signal_user_data_t *ud)
1450 {
1451         GValue *internal;
1452         GHashTableIter iter;
1453         gchar *key;
1454         GValue *gval;
1455
1456
1457         g_debug("ghb_settings_init");
1458         prefs_initializing = TRUE;
1459
1460         internalPlist = ghb_resource_get("internal-defaults");
1461         // Setting a ui widget will cause the corresponding setting
1462         // to be set, but it also triggers a callback that can 
1463         // have the side effect of using other settings values
1464         // that have not yet been set.  So set *all* settings first
1465         // then update the ui.
1466         internal = plist_get_dict(internalPlist, "Initialization");
1467         ghb_dict_iter_init(&iter, internal);
1468         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1469         // pointer will break strict-aliasing rules"
1470         while (g_hash_table_iter_next(
1471                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1472         {
1473                 ghb_settings_set_value(ud->settings, key, gval);
1474         }
1475
1476         internal = plist_get_dict(internalPlist, "Presets");
1477         ghb_dict_iter_init(&iter, internal);
1478         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1479         // pointer will break strict-aliasing rules"
1480         while (g_hash_table_iter_next(
1481                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1482         {
1483                 ghb_settings_set_value(ud->settings, key, gval);
1484         }
1485
1486         internal = plist_get_dict(internalPlist, "Preferences");
1487         ghb_dict_iter_init(&iter, internal);
1488         // middle (void*) cast prevents gcc warning "defreferencing type-punned
1489         // pointer will break strict-aliasing rules"
1490         while (g_hash_table_iter_next(
1491                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1492         {
1493                 ghb_settings_set_value(ud->settings, key, gval);
1494         }
1495         prefs_initializing = FALSE;
1496 }
1497
1498 void
1499 ghb_settings_close()
1500 {
1501         if (internalPlist)
1502                 ghb_value_free(internalPlist);
1503         if (presetsPlist)
1504                 ghb_value_free(presetsPlist);
1505         if (prefsPlist)
1506                 ghb_value_free(prefsPlist);
1507 }
1508
1509 #if defined(_WIN32)
1510 gchar*
1511 FindFirstCDROM(void)
1512 {
1513         gint ii, drives;
1514         gchar drive[5];
1515
1516         strcpy(drive, "A:" G_DIR_SEPARATOR_S);
1517         drives = GetLogicalDrives();
1518         for (ii = 0; ii < 26; ii++)
1519         {
1520                 if (drives & 0x01)
1521                 {
1522                         guint dtype;
1523
1524                         drive[0] = 'A' + ii;
1525                         dtype = GetDriveType(drive);
1526                         if (dtype == DRIVE_CDROM)
1527                         {
1528                                 return g_strdup(drive);
1529                         }
1530                 }
1531                 drives >>= 1;
1532         }
1533         return NULL;
1534 }
1535 #endif
1536
1537 void
1538 ghb_prefs_load(signal_user_data_t *ud)
1539 {
1540         GValue *dict, *internal;
1541         GHashTableIter iter;
1542         gchar *key;
1543         GValue *gval, *path;
1544         
1545         g_debug("ghb_prefs_load");
1546         prefsPlist = load_plist("preferences");
1547         if (prefsPlist == NULL)
1548                 prefsPlist = ghb_dict_value_new();
1549         dict = plist_get_dict(prefsPlist, "Preferences");
1550         internal = plist_get_dict(internalPlist, "Preferences");
1551         if (dict == NULL && internal)
1552         {
1553                 dict = ghb_dict_value_new();
1554                 ghb_dict_insert(prefsPlist, g_strdup("Preferences"), dict);
1555
1556                 // Get defaults from internal defaults 
1557                 ghb_dict_iter_init(&iter, internal);
1558                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
1559                 // pointer will break strict-aliasing rules"
1560                 while (g_hash_table_iter_next(
1561                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
1562                 {
1563                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
1564                 }
1565
1566                 const gchar *dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP);
1567                 if (dir == NULL)
1568                 {
1569                         dir = ".";
1570                 }
1571                 ghb_dict_insert(dict, 
1572                         g_strdup("ExportDirectory"), ghb_value_dup(ghb_string_value(dir)));
1573
1574                 dir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
1575                 if (dir == NULL)
1576                 {
1577                         dir = ".";
1578                 }
1579                 ghb_dict_insert(dict, 
1580                         g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
1581
1582                 ghb_dict_insert(dict, 
1583                         g_strdup("SrtDir"), ghb_value_dup(ghb_string_value(dir)));
1584 #if defined(_WIN32)
1585                 gchar *source;
1586
1587                 source = FindFirstCDROM();
1588                 if (source == NULL)
1589                 {
1590                         source = g_strdup("C:" G_DIR_SEPARATOR_S);
1591                 }
1592                 ghb_dict_insert(dict, g_strdup("default_source"), 
1593                                                 ghb_value_dup(ghb_string_value(source)));
1594                 g_free(source);
1595 #endif
1596                 store_prefs();
1597         }
1598         // Read legacy default_preset preference and update accordingly
1599         path = ghb_dict_lookup(dict, "default_preset");
1600         if (path)
1601         {
1602                 gint *indices, len;
1603
1604                 if (G_VALUE_TYPE(path) == G_TYPE_STRING)
1605                 {
1606                         GValue *str = path;
1607
1608                         path = ghb_array_value_new(1);
1609                         ghb_array_append(path, ghb_value_dup(str));
1610                         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
1611                         ghb_value_free(path);
1612                 }
1613                 else
1614                         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
1615
1616                 if (indices)
1617                 {
1618                         presets_set_default(indices, len);
1619                         g_free(indices);
1620                 }
1621                 ghb_dict_remove(dict, "default_preset");
1622                 store_prefs();
1623         }
1624 }
1625
1626 static const gchar*
1627 get_preset_color(gint type, gboolean folder)
1628 {
1629         const gchar *color;
1630
1631         if (type == PRESETS_CUSTOM)
1632         {
1633                 color = "DimGray";
1634                 if (folder)
1635                 {
1636                         color = "black";
1637                 }
1638         }
1639         else
1640         {
1641                 color = "blue";
1642                 if (folder)
1643                 {
1644                         color = "Navy";
1645                 }
1646         }
1647         return color;
1648 }
1649
1650 void
1651 ghb_presets_list_init(
1652         signal_user_data_t *ud, 
1653         gint *indices,
1654         gint len)
1655 {
1656         GtkTreeView *treeview;
1657         GtkTreeIter iter, titer, *piter;
1658         
1659         GtkTreeStore *store;
1660         const gchar *preset;
1661         GtkTreePath *parent_path;
1662         const gchar *description;
1663         gboolean def;
1664         gint count, ii;
1665         GValue *dict;
1666         gint *more_indices;
1667         GValue *presets = NULL;
1668         
1669         g_debug("ghb_presets_list_init ()");
1670         more_indices = g_malloc((len+1)*sizeof(gint));
1671         memcpy(more_indices, indices, len*sizeof(gint));
1672         presets = presets_get_folder(presetsPlist, indices, len);
1673         if (presets == NULL)
1674         {
1675                 g_warning("Failed to find parent folder when adding child.");
1676                 return;
1677         }
1678         count = ghb_array_len(presets);
1679         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1680         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1681         parent_path = ghb_tree_path_new_from_indices(indices, len);
1682         if (parent_path)
1683         {
1684                 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &titer, parent_path);
1685                 piter = &titer;
1686                 gtk_tree_path_free(parent_path);
1687         }
1688         else
1689         {
1690                 piter = NULL;
1691         }
1692         for (ii = 0; ii < count; ii++)
1693         {
1694                 const gchar *color;
1695                 gint type;
1696                 gboolean folder;
1697
1698                 // Additional settings, add row
1699                 dict = ghb_array_get_nth(presets, ii);
1700                 preset = preset_get_name(dict);
1701                 more_indices[len] = ii;
1702                 def = preset_is_default(dict);
1703
1704                 description = ghb_presets_get_description(dict);
1705                 gtk_tree_store_append(store, &iter, piter);
1706                 type = ghb_preset_type(dict);
1707                 folder = ghb_preset_folder(dict);
1708                 color = get_preset_color(type, folder);
1709                 gtk_tree_store_set(store, &iter, 0, preset, 
1710                                                         1, def ? 800 : 400, 
1711                                                         2, def ? 2 : 0,
1712                                                         3, color, 
1713                                                         4, description,
1714                                                         5, type == PRESETS_BUILTIN ? 0 : 1,
1715                                                         -1);
1716                 if (def && piter)
1717                 {
1718                         GtkTreePath *path;
1719                         GtkTreeIter ppiter;
1720
1721                         if (gtk_tree_model_iter_parent(
1722                                 GTK_TREE_MODEL(store), &ppiter, piter))
1723                         {
1724                                 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &ppiter);
1725                                 gtk_tree_view_expand_row(treeview, path, FALSE);
1726                                 gtk_tree_path_free(path);
1727                         }
1728                         path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), piter);
1729                         gtk_tree_view_expand_row(treeview, path, FALSE);
1730                         gtk_tree_path_free(path);
1731                 }
1732                 if (folder)
1733                 {
1734                         ghb_presets_list_init(ud, more_indices, len+1);
1735                         if (preset_folder_is_open(dict))
1736                         {
1737                                 GtkTreePath *path;
1738
1739                                 if (piter != NULL)
1740                                 {
1741                                         path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), piter);
1742                                         gtk_tree_view_expand_row(treeview, path, FALSE);
1743                                         gtk_tree_path_free(path);
1744                                 }
1745                                 path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
1746                                 gtk_tree_view_expand_row(treeview, path, FALSE);
1747                                 gtk_tree_path_free(path);
1748                         }
1749                 }
1750         }
1751         g_free(more_indices);
1752 }
1753
1754 static void
1755 presets_list_update_item(
1756         signal_user_data_t *ud, 
1757         gint *indices,
1758         gint len,
1759         gboolean recurse)
1760 {
1761         GtkTreeView *treeview;
1762         GtkTreeStore *store;
1763         GtkTreeIter iter;
1764         GtkTreePath *treepath;
1765         const gchar *name;
1766         const gchar *description;
1767         gint type;
1768         gboolean def, folder;
1769         GValue *dict;
1770         const gchar *color;
1771         
1772         g_debug("presets_list_update_item ()");
1773         dict = presets_get_dict(presetsPlist, indices, len);
1774         if (dict == NULL)
1775                 return;
1776         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1777         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1778         treepath = ghb_tree_path_new_from_indices(indices, len);
1779         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
1780         // Additional settings, add row
1781         name = preset_get_name(dict);
1782         def = preset_is_default(dict);
1783
1784         description = ghb_presets_get_description(dict);
1785         type = ghb_preset_type(dict);
1786         folder = ghb_preset_folder(dict);
1787         color = get_preset_color(type, folder);
1788         gtk_tree_store_set(store, &iter, 0, name, 
1789                                                 1, def ? 800 : 400, 
1790                                                 2, def ? 2 : 0,
1791                                                 3, color,
1792                                                 4, description,
1793                                                 5, type == PRESETS_BUILTIN ? 0 : 1,
1794                                                 -1);
1795         if (recurse && folder)
1796         {
1797                 ghb_presets_list_init(ud, indices, len);
1798         }
1799 }
1800
1801 static void
1802 presets_list_insert(
1803         signal_user_data_t *ud, 
1804         gint *indices,
1805         gint len)
1806 {
1807         GtkTreeView *treeview;
1808         GtkTreeIter iter, titer, *piter;
1809         GtkTreeStore *store;
1810         const gchar *preset;
1811         const gchar *description;
1812         gint type;
1813         gboolean def, folder;
1814         gint count;
1815         GValue *presets;
1816         GtkTreePath *parent_path;
1817         GValue *dict;
1818         const gchar *color;
1819         
1820         g_debug("presets_list_insert ()");
1821         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1822         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1823         presets = presets_get_folder(presetsPlist, indices, len-1);
1824         if (presets == NULL)
1825         {
1826                 g_warning("Failed to find parent folder while adding child.");
1827                 return;
1828         }
1829         parent_path = ghb_tree_path_new_from_indices(indices, len-1);
1830         if (parent_path)
1831         {
1832                 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &titer, parent_path);
1833                 piter = &titer;
1834                 gtk_tree_path_free(parent_path);
1835         }
1836         else
1837         {
1838                 piter = NULL;
1839         }
1840         count = ghb_array_len(presets);
1841         if (indices[len-1] >= count)
1842                 return;
1843         // Additional settings, add row
1844         dict = ghb_array_get_nth(presets, indices[len-1]);
1845         preset = preset_get_name(dict);
1846         def = preset_is_default(dict);
1847
1848         description = ghb_presets_get_description(dict);
1849         gtk_tree_store_insert(store, &iter, piter, indices[len-1]);
1850         type = ghb_preset_type(dict);
1851         folder = ghb_preset_folder(dict);
1852         color = get_preset_color(type, folder);
1853         gtk_tree_store_set(store, &iter, 0, preset, 
1854                                                 1, def ? 800 : 400, 
1855                                                 2, def ? 2 : 0,
1856                                                 3, color,
1857                                                 4, description,
1858                                                 5, type == PRESETS_BUILTIN ? 0 : 1,
1859                                                 -1);
1860         if (folder)
1861         {
1862                 ghb_presets_list_init(ud, indices, len);
1863         }
1864 }
1865
1866 static void
1867 presets_list_remove(
1868         signal_user_data_t *ud, 
1869         gint *indices,
1870         gint len)
1871 {
1872         GtkTreeView *treeview;
1873         GtkTreePath *treepath;
1874         GtkTreeIter iter;
1875         GtkTreeStore *store;
1876         
1877         g_debug("presets_list_remove ()");
1878         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1879         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
1880         treepath = ghb_tree_path_new_from_indices(indices, len);
1881         if (treepath)
1882         {
1883                 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath))
1884                         gtk_tree_store_remove(store, &iter);
1885                 gtk_tree_path_free(treepath);
1886         }
1887 }
1888
1889 static void
1890 remove_std_presets(signal_user_data_t *ud)
1891 {
1892         gint count, ii;
1893         gint indices = 0;
1894
1895         count = ghb_array_len(presetsPlist);
1896         for (ii = count-1; ii >= 0; ii--)
1897         {
1898                 GValue *dict;
1899                 gint ptype;
1900
1901                 dict = ghb_array_get_nth(presetsPlist, ii);
1902                 ptype = ghb_value_int(preset_dict_get_value(dict, "Type"));
1903                 if (ptype == PRESETS_BUILTIN)
1904                 {
1905                         if (ghb_presets_remove(presetsPlist, &indices, 1))
1906                         {
1907                                 presets_list_remove(ud, &indices, 1);
1908                         }
1909                 }
1910         }
1911 }
1912
1913 void
1914 ghb_save_queue(GValue *queue)
1915 {
1916         pid_t pid;
1917         char *path;
1918
1919         pid = getpid();
1920         path = g_strdup_printf ("queue.%d", pid);
1921         store_plist(queue, path);
1922         g_free(path);
1923 }
1924
1925 GValue*
1926 ghb_load_queue()
1927 {
1928         GValue *queue;
1929         pid_t pid;
1930         char *path;
1931
1932         pid = getpid();
1933         path = g_strdup_printf ("queue.%d", pid);
1934         queue = load_plist(path);
1935         g_free(path);
1936         return queue;
1937 }
1938
1939 GValue*
1940 ghb_load_old_queue(int pid)
1941 {
1942         GValue *queue;
1943         char *path;
1944
1945         path = g_strdup_printf ("queue.%d", pid);
1946         queue = load_plist(path);
1947         g_free(path);
1948         return queue;
1949 }
1950
1951 void
1952 ghb_remove_old_queue_file(int pid)
1953 {
1954         char *path;
1955
1956         path = g_strdup_printf ("queue.%d", pid);
1957         remove_plist(path);
1958         g_free(path);
1959 }
1960
1961 void
1962 ghb_remove_queue_file()
1963 {
1964         pid_t pid;
1965         char *path;
1966
1967         pid = getpid();
1968         path = g_strdup_printf ("queue.%d", pid);
1969         remove_plist(path);
1970         g_free(path);
1971 }
1972
1973 typedef struct
1974 {
1975         gchar *mac_val;
1976         gchar *lin_val;
1977 } value_map_t;
1978
1979 static value_map_t vcodec_xlat[] =
1980 {
1981         {"MPEG-4 (FFmpeg)", "ffmpeg"},
1982         {"MPEG-4 (XviD)", "ffmpeg"},
1983         {"H.264 (x264)", "x264"},
1984         {"VP3 (Theora)", "theora"},
1985         {NULL,NULL}
1986 };
1987
1988 static value_map_t acodec_xlat[] =
1989 {
1990         {"AAC (faac)", "faac"},
1991         {"AAC (CoreAudio)", "faac"},
1992         {"AC3 Passthru", "ac3"},
1993         {"MP3 (lame)", "lame"},
1994         {"Vorbis (vorbis)", "vorbis"},
1995         {NULL,NULL}
1996 };
1997
1998 value_map_t container_xlat[] =
1999 {
2000         {"MP4 file", "mp4"},
2001         {"M4V file", "mp4"},
2002         {"MKV file", "mkv"},
2003         {"AVI file", "mkv"},
2004         {"OGM file", "mkv"},
2005         {NULL, NULL}
2006 };
2007
2008 value_map_t framerate_xlat[] =
2009 {
2010         {"Same as source", "source"},
2011         {"5", "5"},
2012         {"10", "10"},
2013         {"12", "12"},
2014         {"15", "15"},
2015         {"23.976", "23.976"},
2016         {"24", "24"},
2017         {"25", "25"},
2018         {"29.97", "29.97"},
2019         {NULL, NULL}
2020 };
2021
2022 value_map_t samplerate_xlat[] =
2023 {
2024         {"Auto", "source"},
2025         {"22.05", "22.05"},
2026         {"24", "24"},
2027         {"32", "32"},
2028         {"44.1", "44.1"},
2029         {"48", "48"},
2030         {NULL, NULL}
2031 };
2032
2033 value_map_t mix_xlat[] =
2034 {
2035         {"Mono", "mono"},
2036         {"Stereo", "stereo"},
2037         {"Dolby Surround", "dpl1"},
2038         {"Dolby Pro Logic II", "dpl2"},
2039         {"6-channel discrete", "6ch"},
2040         {"AC3 Passthru", "none"},
2041         {NULL, NULL}
2042 };
2043
2044 value_map_t deint_xlat[] =
2045 {
2046         {"0", "off"},
2047         {"1", "custom"},
2048         {"2", "fast"},
2049         {"3", "slow"},
2050         {"4", "slower"},
2051         {NULL, NULL}
2052 };
2053
2054 value_map_t denoise_xlat[] =
2055 {
2056         {"0", "off"},
2057         {"1", "custom"},
2058         {"2", "weak"},
2059         {"3", "medium"},
2060         {"4", "strong"},
2061         {NULL, NULL}
2062 };
2063
2064 value_map_t detel_xlat[] =
2065 {
2066         {"0", "off"},
2067         {"1", "custom"},
2068         {"2", "default"},
2069         {NULL, NULL}
2070 };
2071
2072 value_map_t decomb_xlat[] =
2073 {
2074         {"0", "off"},
2075         {"1", "custom"},
2076         {"2", "default"},
2077         {NULL, NULL}
2078 };
2079
2080 extern iso639_lang_t ghb_language_table[];
2081
2082 static GValue*
2083 export_lang_xlat2(GValue *lin_val)
2084 {
2085         GValue *gval;
2086
2087         if (lin_val == NULL) return NULL;
2088         gint ii;
2089         gchar *str;
2090
2091         str = ghb_value_string(lin_val);
2092         for (ii = 0; ghb_language_table[ii].eng_name; ii++)
2093         {
2094                 if (strcmp(str, ghb_language_table[ii].iso639_2) == 0)
2095                 {
2096                         const gchar *lang;
2097
2098                         if (ghb_language_table[ii].native_name[0] != 0)
2099                                 lang = ghb_language_table[ii].native_name;
2100                         else
2101                                 lang = ghb_language_table[ii].eng_name;
2102
2103                         gval = ghb_string_value_new(lang);
2104                         g_free(str);
2105                         return gval;
2106                 }
2107         }
2108         g_debug("Can't map language value: (%s)", str);
2109         g_free(str);
2110         return NULL;
2111 }
2112
2113 static GValue*
2114 export_subtitle_xlat2(GValue *lin_val)
2115 {
2116         gchar *str;
2117         GValue *gval;
2118
2119         if (lin_val == NULL) return NULL;
2120         str = ghb_value_string(lin_val);
2121         if (strcmp(str, "none") == 0)
2122         {
2123                 gval = ghb_string_value_new("None");
2124         }
2125         else if (strcmp(str, "auto") == 0)
2126         {
2127                 gval = ghb_string_value_new("Autoselect");
2128         }
2129         else
2130         {
2131                 gval = export_lang_xlat2(lin_val);
2132         }
2133         g_free(str);
2134         return gval;
2135 }
2136
2137 static GValue*
2138 import_lang_xlat2(GValue *mac_val)
2139 {
2140         GValue *gval;
2141
2142         if (mac_val == NULL) return NULL;
2143         gint ii;
2144         gchar *str;
2145
2146         str = ghb_value_string(mac_val);
2147         for (ii = 0; ghb_language_table[ii].eng_name; ii++)
2148         {
2149                 if ((strcmp(str, ghb_language_table[ii].eng_name) == 0) ||
2150                         (strcmp(str, ghb_language_table[ii].native_name) == 0))
2151                 {
2152                         gval = ghb_string_value_new(ghb_language_table[ii].iso639_2);
2153                         g_free(str);
2154                         return gval;
2155                 }
2156         }
2157         g_debug("Can't map language value: (%s)", str);
2158         g_free(str);
2159         return NULL;
2160 }
2161
2162 static GValue*
2163 import_subtitle_xlat2(GValue *mac_val)
2164 {
2165         gchar *str;
2166         GValue *gval;
2167
2168         if (mac_val == NULL) return NULL;
2169         str = ghb_value_string(mac_val);
2170         if (strcmp(str, "None") == 0)
2171         {
2172                 gval = ghb_string_value_new("none");
2173         }
2174         else if (strcmp(str, "Autoselect") == 0)
2175         {
2176                 gval = ghb_string_value_new("auto");
2177         }
2178         else
2179         {
2180                 gval = import_lang_xlat2(mac_val);
2181         }
2182         g_free(str);
2183         return gval;
2184 }
2185
2186 static GValue*
2187 export_audio_track_xlat2(GValue *lin_val)
2188 {
2189         gchar *str;
2190         GValue *gval = NULL;
2191
2192         if (lin_val == NULL) return NULL;
2193         str = ghb_value_string(lin_val);
2194         if (strcmp(str, "none") == 0)
2195         {
2196                 gval = ghb_int_value_new(1);
2197         }
2198         else
2199         {
2200                 gint val = ghb_value_int(lin_val) + 1;
2201                 gval = ghb_int_value_new(val);
2202         }
2203         g_free(str);
2204         return gval;
2205 }
2206
2207 static GValue*
2208 import_audio_track_xlat2(GValue *mac_val)
2209 {
2210         gint val;
2211         gchar *str;
2212         GValue *gval;
2213
2214         if (mac_val == NULL) return NULL;
2215         val = ghb_value_int(mac_val);
2216         if (val <= 0)
2217         {
2218                 val = 0;
2219         }
2220         else
2221         {
2222                 val--;
2223         }
2224         str = g_strdup_printf("%d", val);
2225         gval = ghb_string_value_new(str);
2226         g_free(str);
2227         return gval;
2228 }
2229
2230 static GValue*
2231 export_value_xlat2(value_map_t *value_map, GValue *lin_val, GType mac_type)
2232 {
2233         GValue *gval;
2234
2235         if (lin_val == NULL) return NULL;
2236         gint ii;
2237         gchar *str;
2238         GValue *sval;
2239
2240         str = ghb_value_string(lin_val);
2241         for (ii = 0; value_map[ii].mac_val; ii++)
2242         {
2243                 if (strcmp(str, value_map[ii].lin_val) == 0)
2244                 {
2245                         sval = ghb_string_value_new(value_map[ii].mac_val);
2246                         g_free(str);
2247                         gval = ghb_value_new(mac_type);
2248                         if (!g_value_transform(sval, gval))
2249                         {
2250                                 g_warning("can't transform");
2251                                 ghb_value_free(gval);
2252                                 ghb_value_free(sval);
2253                                 return NULL;
2254                         }
2255                         ghb_value_free(sval);
2256                         return gval;
2257                 }
2258         }
2259         g_debug("Can't map value: (%s)", str);
2260         g_free(str);
2261         return NULL;
2262 }
2263
2264 static void
2265 export_value_xlat(GValue *dict)
2266 {
2267         GValue *lin_val, *gval;
2268         const gchar *key;
2269
2270         key = "VideoEncoder";
2271         lin_val = ghb_dict_lookup(dict, key);
2272         gval = export_value_xlat2(vcodec_xlat, lin_val, G_TYPE_STRING);
2273         if (gval)
2274                 ghb_dict_insert(dict, g_strdup(key), gval);
2275         key = "FileFormat";
2276         lin_val = ghb_dict_lookup(dict, key);
2277         gval = export_value_xlat2(container_xlat, lin_val, G_TYPE_STRING);
2278         if (gval)
2279                 ghb_dict_insert(dict, g_strdup(key), gval);
2280         key = "VideoFramerate";
2281         lin_val = ghb_dict_lookup(dict, key);
2282         gval = export_value_xlat2(framerate_xlat, lin_val, G_TYPE_STRING);
2283         if (gval)
2284                 ghb_dict_insert(dict, g_strdup(key), gval);
2285         key = "PictureDetelecine";
2286         lin_val = ghb_dict_lookup(dict, key);
2287         gval = export_value_xlat2(detel_xlat, lin_val, G_TYPE_INT);
2288         if (gval)
2289                 ghb_dict_insert(dict, g_strdup(key), gval);
2290         key = "PictureDecomb";
2291         lin_val = ghb_dict_lookup(dict, key);
2292         gval = export_value_xlat2(decomb_xlat, lin_val, G_TYPE_INT);
2293         if (gval)
2294                 ghb_dict_insert(dict, g_strdup(key), gval);
2295         key = "PictureDeinterlace";
2296         lin_val = ghb_dict_lookup(dict, key);
2297         gval = export_value_xlat2(deint_xlat, lin_val, G_TYPE_INT);
2298         if (gval)
2299                 ghb_dict_insert(dict, g_strdup(key), gval);
2300         key = "PictureDenoise";
2301         lin_val = ghb_dict_lookup(dict, key);
2302         gval = export_value_xlat2(denoise_xlat, lin_val, G_TYPE_INT);
2303         if (gval)
2304                 ghb_dict_insert(dict, g_strdup(key), gval);
2305
2306         GValue *slist;
2307         GValue *sdict;
2308         gint count, ii;
2309
2310         slist = ghb_dict_lookup(dict, "SubtitleList");
2311         count = ghb_array_len(slist);
2312         for (ii = 0; ii < count; ii++)
2313         {
2314                 sdict = ghb_array_get_nth(slist, ii);
2315                 key = "SubtitleLanguage";
2316                 lin_val = ghb_dict_lookup(sdict, key);
2317                 gval = export_subtitle_xlat2(lin_val);
2318                 if (gval)
2319                         ghb_dict_insert(sdict, g_strdup(key), gval);
2320         }
2321
2322         GValue *alist;
2323         GValue *adict;
2324
2325         alist = ghb_dict_lookup(dict, "AudioList");
2326         count = ghb_array_len(alist);
2327         for (ii = 0; ii < count; ii++)
2328         {
2329                 adict = ghb_array_get_nth(alist, ii);
2330                 key = "AudioTrack";
2331                 lin_val = ghb_dict_lookup(adict, key);
2332                 gval = export_audio_track_xlat2(lin_val);
2333                 if (gval)
2334                         ghb_dict_insert(adict, g_strdup(key), gval);
2335                 key = "AudioEncoder";
2336                 lin_val = ghb_dict_lookup(adict, key);
2337                 gval = export_value_xlat2(acodec_xlat, lin_val, G_TYPE_STRING);
2338                 if (gval)
2339                         ghb_dict_insert(adict, g_strdup(key), gval);
2340                 key = "AudioSamplerate";
2341                 lin_val = ghb_dict_lookup(adict, key);
2342                 gval = export_value_xlat2(samplerate_xlat, lin_val, G_TYPE_STRING);
2343                 if (gval)
2344                         ghb_dict_insert(adict, g_strdup(key), gval);
2345                 key = "AudioMixdown";
2346                 lin_val = ghb_dict_lookup(adict, key);
2347                 gval = export_value_xlat2(mix_xlat, lin_val, G_TYPE_STRING);
2348                 if (gval)
2349                         ghb_dict_insert(adict, g_strdup(key), gval);
2350         }
2351 }
2352
2353
2354 static GValue*
2355 import_value_xlat2(
2356         GValue *defaults, 
2357         value_map_t *value_map,
2358         const gchar *key, 
2359         GValue *mac_val)
2360 {
2361         GValue *gval, *def_val;
2362
2363         if (mac_val == NULL) return NULL;
2364         def_val = ghb_dict_lookup(defaults, key);
2365         if (def_val)
2366         {
2367                 gint ii;
2368                 gchar *str;
2369                 GValue *sval;
2370
2371                 str = ghb_value_string(mac_val);
2372                 for (ii = 0; value_map[ii].mac_val; ii++)
2373                 {
2374                         if (strcmp(str, value_map[ii].mac_val) == 0)
2375                         {
2376                                 sval = ghb_string_value_new(value_map[ii].lin_val);
2377                                 g_free(str);
2378                                 gval = ghb_value_new(G_VALUE_TYPE(def_val));
2379                                 if (!g_value_transform(sval, gval))
2380                                 {
2381                                         g_warning("can't transform");
2382                                         ghb_value_free(gval);
2383                                         ghb_value_free(sval);
2384                                         return NULL;
2385                                 }
2386                                 ghb_value_free(sval);
2387                                 return gval;
2388                         }
2389                 }
2390                 g_free(str);
2391         }
2392         else
2393         {
2394                 gint ii;
2395                 gchar *str;
2396                 GValue *sval;
2397
2398                 str = ghb_value_string(mac_val);
2399                 for (ii = 0; value_map[ii].mac_val; ii++)
2400                 {
2401                         if (strcmp(str, value_map[ii].mac_val) == 0)
2402                         {
2403                                 sval = ghb_string_value_new(value_map[ii].lin_val);
2404                                 g_free(str);
2405                                 gval = ghb_value_new(G_VALUE_TYPE(mac_val));
2406                                 if (!g_value_transform(sval, gval))
2407                                 {
2408                                         g_warning("can't transform");
2409                                         ghb_value_free(gval);
2410                                         ghb_value_free(sval);
2411                                         return NULL;
2412                                 }
2413                                 ghb_value_free(sval);
2414                                 return gval;
2415                         }
2416                 }
2417                 g_free(str);
2418         }
2419         return NULL;
2420 }
2421
2422 static void
2423 import_value_xlat(GValue *dict)
2424 {
2425         GValue *defaults, *mac_val, *gval;
2426         const gchar *key;
2427
2428         defaults = plist_get_dict(internalPlist, "Presets");
2429         key = "VideoEncoder";
2430         mac_val = ghb_dict_lookup(dict, key);
2431         gval = import_value_xlat2(defaults, vcodec_xlat, key, mac_val);
2432         if (gval)
2433                 ghb_dict_insert(dict, g_strdup(key), gval);
2434         key = "FileFormat";
2435         mac_val = ghb_dict_lookup(dict, key);
2436         gval = import_value_xlat2(defaults, container_xlat, key, mac_val);
2437         if (gval)
2438                 ghb_dict_insert(dict, g_strdup(key), gval);
2439         key = "VideoFramerate";
2440         mac_val = ghb_dict_lookup(dict, key);
2441         gval = import_value_xlat2(defaults, framerate_xlat, key, mac_val);
2442         if (gval)
2443                 ghb_dict_insert(dict, g_strdup(key), gval);
2444         key = "PictureDetelecine";
2445         mac_val = ghb_dict_lookup(dict, key);
2446         gval = import_value_xlat2(defaults, detel_xlat, key, mac_val);
2447         if (gval)
2448                 ghb_dict_insert(dict, g_strdup(key), gval);
2449         key = "PictureDecomb";
2450         mac_val = ghb_dict_lookup(dict, key);
2451         gval = import_value_xlat2(defaults, decomb_xlat, key, mac_val);
2452         if (gval)
2453                 ghb_dict_insert(dict, g_strdup(key), gval);
2454         key = "PictureDeinterlace";
2455         mac_val = ghb_dict_lookup(dict, key);
2456         gval = import_value_xlat2(defaults, deint_xlat, key, mac_val);
2457         if (gval)
2458                 ghb_dict_insert(dict, g_strdup(key), gval);
2459         key = "PictureDenoise";
2460         mac_val = ghb_dict_lookup(dict, key);
2461         gval = import_value_xlat2(defaults, denoise_xlat, key, mac_val);
2462         if (gval)
2463                 ghb_dict_insert(dict, g_strdup(key), gval);
2464
2465
2466         GValue *sdeflist;
2467         GValue *sdefaults;
2468         GValue *slist;
2469         GValue *sdict;
2470         gint count, ii;
2471
2472         sdeflist = ghb_dict_lookup(defaults, "SubtitleList");
2473         if (sdeflist)
2474         {
2475                 slist = ghb_dict_lookup(dict, "SubtitleList");
2476                 if (slist)
2477                 {
2478                         sdefaults = ghb_array_get_nth(sdeflist, 0);
2479                         count = ghb_array_len(slist);
2480                         for (ii = 0; ii < count; ii++)
2481                         {
2482                                 sdict = ghb_array_get_nth(slist, ii);
2483                                 key = "SubtitleLanguage";
2484                                 mac_val = ghb_dict_lookup(sdict, key);
2485                                 gval = import_subtitle_xlat2(mac_val);
2486                                 if (gval)
2487                                         ghb_dict_insert(sdict, g_strdup(key), gval);
2488                         }
2489                 
2490                 }
2491                 else
2492                 {
2493                         key = "Subtitles";
2494                         mac_val = ghb_dict_lookup(dict, key);
2495                         slist = ghb_array_value_new(8);
2496                         ghb_dict_insert(dict, g_strdup("SubtitleList"), slist);
2497                         if (mac_val)
2498                         {
2499                                 gchar *lang;
2500         
2501                                 gval = import_subtitle_xlat2(mac_val);
2502                                 lang = ghb_value_string(gval);
2503                                 if (lang && strcasecmp(lang, "none") != 0 && !slist)
2504                                 {
2505                                         sdict = ghb_dict_value_new();
2506                                         ghb_array_append(slist, sdict);
2507                                         ghb_dict_insert(sdict, g_strdup("SubtitleLanguage"), gval);
2508                                         gval = ghb_dict_lookup(dict, "SubtitlesForced");
2509                                         if (gval != NULL)
2510                                         {
2511                                                 ghb_dict_insert(sdict, g_strdup("SubtitleForced"), 
2512                                                                                 ghb_value_dup(gval));
2513                                         }
2514                                         else
2515                                         {
2516                                                 ghb_dict_insert(sdict, g_strdup("SubtitleForced"), 
2517                                                                                 ghb_boolean_value_new(FALSE));
2518                                         }
2519                                         ghb_dict_insert(sdict, g_strdup("SubtitleBurned"),
2520                                                                         ghb_boolean_value_new(TRUE));
2521                                         ghb_dict_insert(sdict, g_strdup("SubtitleDefaultTrack"),
2522                                                                         ghb_boolean_value_new(FALSE));
2523                                 }
2524                                 else
2525                                 {
2526                                         ghb_value_free(gval);
2527                                 }
2528                                 if (lang)
2529                                         g_free(lang);
2530                         }
2531                 }
2532         }
2533         ghb_dict_remove(dict, "Subtitles");
2534         ghb_dict_remove(dict, "SubtitlesForced");
2535
2536
2537         GValue *alist;
2538         GValue *adict;
2539         GValue *adefaults;
2540         GValue *adeflist;
2541
2542         adeflist = ghb_dict_lookup(defaults, "AudioList");
2543         if (adeflist)
2544         {
2545                 adefaults = ghb_array_get_nth(adeflist, 0);
2546                 alist = ghb_dict_lookup(dict, "AudioList");
2547                 count = ghb_array_len(alist);
2548                 for (ii = 0; ii < count; ii++)
2549                 {
2550                         adict = ghb_array_get_nth(alist, ii);
2551                         key = "AudioTrack";
2552                         mac_val = ghb_dict_lookup(adict, key);
2553                         gval = import_audio_track_xlat2(mac_val);
2554                         if (gval)
2555                                 ghb_dict_insert(adict, g_strdup(key), gval);
2556                         key = "AudioEncoder";
2557                         mac_val = ghb_dict_lookup(adict, key);
2558                         gval = import_value_xlat2(adefaults, acodec_xlat, key, mac_val);
2559                         if (gval)
2560                                 ghb_dict_insert(adict, g_strdup(key), gval);
2561                         key = "AudioSamplerate";
2562                         mac_val = ghb_dict_lookup(adict, key);
2563                         gval = import_value_xlat2(adefaults, samplerate_xlat, key, mac_val);
2564                         if (gval)
2565                                 ghb_dict_insert(adict, g_strdup(key), gval);
2566                         key = "AudioMixdown";
2567                         mac_val = ghb_dict_lookup(adict, key);
2568                         gval = import_value_xlat2(adefaults, mix_xlat, key, mac_val);
2569                         if (gval)
2570                                 ghb_dict_insert(adict, g_strdup(key), gval);
2571
2572                         mac_val = ghb_dict_lookup(adict, "AudioTrackDRCSlider");
2573                         if (mac_val != NULL)
2574                         {
2575                                 gdouble drc;
2576                                 drc = ghb_value_double(mac_val);
2577                                 if (drc < 1.0 && drc > 0.0)
2578                                 {
2579                                         ghb_dict_insert(adict, g_strdup("AudioTrackDRCSlider"), 
2580                                                                         ghb_double_value_new(0.0));
2581                                 }
2582                         }
2583                 }
2584         }
2585 }
2586
2587 static void
2588 import_xlat_preset(GValue *dict)
2589 {
2590         gboolean uses_max;
2591         gint uses_pic;
2592         gint par;
2593         gint vqtype;
2594
2595         g_debug("import_xlat_preset ()");
2596         uses_max = ghb_value_boolean(
2597                                                 preset_dict_get_value(dict, "UsesMaxPictureSettings"));
2598         uses_pic = ghb_value_int(
2599                                                 preset_dict_get_value(dict, "UsesPictureSettings"));
2600         par = ghb_value_int(preset_dict_get_value(dict, "PicturePAR"));
2601         vqtype = ghb_value_int(preset_dict_get_value(dict, "VideoQualityType"));
2602
2603         if (uses_max || uses_pic == 2)
2604         {
2605                 ghb_dict_insert(dict, g_strdup("autoscale"), 
2606                                                 ghb_boolean_value_new(TRUE));
2607         }
2608         switch (par)
2609         {
2610         case 0:
2611         {
2612                 if (ghb_dict_lookup(dict, "PictureModulus") == NULL)
2613                         ghb_dict_insert(dict, g_strdup("PictureModulus"), 
2614                                                         ghb_int_value_new(16));
2615         } break;
2616         case 1:
2617         {
2618                 ghb_dict_insert(dict, g_strdup("PictureModulus"), 
2619                                                 ghb_int_value_new(1));
2620         } break;
2621         case 2:
2622         {
2623                 if (ghb_dict_lookup(dict, "PictureModulus") == NULL)
2624                         ghb_dict_insert(dict, g_strdup("PictureModulus"), 
2625                                                         ghb_int_value_new(16));
2626         } break;
2627         default:
2628         {
2629                 if (ghb_dict_lookup(dict, "PictureModulus") == NULL)
2630                         ghb_dict_insert(dict, g_strdup("PictureModulus"), 
2631                                                         ghb_int_value_new(16));
2632         } break;
2633         }
2634         // VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
2635         switch (vqtype)
2636         {
2637         case 0:
2638         {
2639                 ghb_dict_insert(dict, g_strdup("vquality_type_target"), 
2640                                                 ghb_boolean_value_new(TRUE));
2641                 ghb_dict_insert(dict, g_strdup("vquality_type_bitrate"), 
2642                                                 ghb_boolean_value_new(FALSE));
2643                 ghb_dict_insert(dict, g_strdup("vquality_type_constant"), 
2644                                                 ghb_boolean_value_new(FALSE));
2645         } break;
2646         case 1:
2647         {
2648                 ghb_dict_insert(dict, g_strdup("vquality_type_target"), 
2649                                                 ghb_boolean_value_new(FALSE));
2650                 ghb_dict_insert(dict, g_strdup("vquality_type_bitrate"), 
2651                                                 ghb_boolean_value_new(TRUE));
2652                 ghb_dict_insert(dict, g_strdup("vquality_type_constant"), 
2653                                                 ghb_boolean_value_new(FALSE));
2654         } break;
2655         case 2:
2656         {
2657                 ghb_dict_insert(dict, g_strdup("vquality_type_target"), 
2658                                                 ghb_boolean_value_new(FALSE));
2659                 ghb_dict_insert(dict, g_strdup("vquality_type_bitrate"), 
2660                                                 ghb_boolean_value_new(FALSE));
2661                 ghb_dict_insert(dict, g_strdup("vquality_type_constant"), 
2662                                                 ghb_boolean_value_new(TRUE));
2663         } break;
2664         default:
2665         {
2666                 ghb_dict_insert(dict, g_strdup("vquality_type_target"), 
2667                                                 ghb_boolean_value_new(FALSE));
2668                 ghb_dict_insert(dict, g_strdup("vquality_type_bitrate"), 
2669                                                 ghb_boolean_value_new(FALSE));
2670                 ghb_dict_insert(dict, g_strdup("vquality_type_constant"), 
2671                                                 ghb_boolean_value_new(TRUE));
2672         } break;
2673         }
2674         import_value_xlat(dict);
2675
2676         gdouble vquality;
2677         const GValue *gval;
2678
2679         vquality = ghb_value_double(preset_dict_get_value(dict, "VideoQualitySlider"));
2680         if (vquality > 0.0 && vquality < 1.0)
2681         {
2682                 gint vcodec;
2683
2684                 gval = preset_dict_get_value(dict, "VideoEncoder");
2685                 vcodec = ghb_lookup_combo_int("VideoEncoder", gval);
2686                 switch (vcodec)
2687                 {
2688                         case HB_VCODEC_X264:
2689                         {
2690                                 vquality = 51. - vquality * 51.;
2691                         } break;
2692
2693                         case HB_VCODEC_FFMPEG:
2694                         {
2695                                 vquality = 31. - vquality * 30.;
2696                         } break;
2697
2698                         case HB_VCODEC_THEORA:
2699                         {
2700                                 vquality = vquality * 63.;
2701                         } break;
2702
2703                         default:
2704                         {
2705                                 vquality = 0.;
2706                         } break;
2707                 }
2708                 ghb_dict_insert(dict, g_strdup("VideoQualitySlider"), 
2709                                                 ghb_double_value_new(vquality));
2710         }
2711 }
2712
2713 static void
2714 import_xlat_presets(GValue *presets)
2715 {
2716         gint count, ii;
2717         GValue *dict;
2718         gboolean folder;
2719
2720         g_debug("import_xlat_presets ()");
2721         if (presets == NULL) return;
2722         count = ghb_array_len(presets);
2723         for (ii = 0; ii < count; ii++)
2724         {
2725                 dict = ghb_array_get_nth(presets, ii);
2726                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
2727                 if (folder)
2728                 {
2729                         GValue *nested;
2730
2731                         nested = ghb_dict_lookup(dict, "ChildrenArray");
2732                         import_xlat_presets(nested);
2733                 }
2734                 else
2735                 {
2736                         import_xlat_preset(dict);
2737                 }
2738         }
2739 }
2740
2741 static void
2742 export_xlat_preset(GValue *dict)
2743 {
2744         gboolean autoscale, target, br, constant;
2745
2746         g_debug("export_xlat_prest ()");
2747         autoscale = ghb_value_boolean(preset_dict_get_value(dict, "autoscale"));
2748         target = ghb_value_boolean(
2749                                 preset_dict_get_value(dict, "vquality_type_target"));
2750         br = ghb_value_boolean(
2751                                 preset_dict_get_value(dict, "vquality_type_bitrate"));
2752         constant = ghb_value_boolean(
2753                                 preset_dict_get_value(dict, "vquality_type_constant"));
2754
2755         if (autoscale)
2756                 ghb_dict_insert(dict, g_strdup("UsesPictureSettings"), 
2757                                                 ghb_int_value_new(2));
2758         else
2759                 ghb_dict_insert(dict, g_strdup("UsesPictureSettings"), 
2760                                                 ghb_int_value_new(1));
2761
2762         // VideoQualityType/0/1/2 - vquality_type_/target/bitrate/constant
2763         if (target)
2764         {
2765                 ghb_dict_insert(dict, g_strdup("VideoQualityType"), 
2766                                                 ghb_int_value_new(0));
2767         }
2768         else if (br)
2769         {
2770                 ghb_dict_insert(dict, g_strdup("VideoQualityType"), 
2771                                                 ghb_int_value_new(1));
2772         }
2773         else if (constant)
2774         {
2775                 ghb_dict_insert(dict, g_strdup("VideoQualityType"), 
2776                                                 ghb_int_value_new(2));
2777         }
2778
2779         GValue *alist, *adict;
2780         gint count, ii;
2781
2782         alist = ghb_dict_lookup(dict, "AudioList");
2783         count = ghb_array_len(alist);
2784         for (ii = 0; ii < count; ii++)
2785         {
2786                 gdouble drc;
2787
2788                 adict = ghb_array_get_nth(alist, ii);
2789                 drc = ghb_value_double(
2790                                 preset_dict_get_value(adict, "AudioTrackDRCSlider"));
2791                 if (drc < 1.0 && drc > 0.0)
2792                 {
2793                         ghb_dict_insert(adict, g_strdup("AudioTrackDRCSlider"), 
2794                                                         ghb_double_value_new(0.0));
2795                 }
2796         }
2797
2798         ghb_dict_remove(dict, "UsesMaxPictureSettings");
2799         ghb_dict_remove(dict, "autoscale");
2800         ghb_dict_remove(dict, "vquality_type_target");
2801         ghb_dict_remove(dict, "vquality_type_bitrate");
2802         ghb_dict_remove(dict, "vquality_type_constant");
2803         export_value_xlat(dict);
2804 }
2805
2806 static void
2807 export_xlat_presets(GValue *presets)
2808 {
2809         gint count, ii;
2810         GValue *dict;
2811         gboolean folder;
2812
2813         if (presets == NULL) return;
2814         count = ghb_array_len(presets);
2815         for (ii = 0; ii < count; ii++)
2816         {
2817                 dict = ghb_array_get_nth(presets, ii);
2818                 folder = ghb_value_boolean(preset_dict_get_value(dict, "Folder"));
2819                 if (folder)
2820                 {
2821                         GValue *nested;
2822
2823                         nested = ghb_dict_lookup(dict, "ChildrenArray");
2824                         export_xlat_presets(nested);
2825                 }
2826                 else
2827                 {
2828                         export_xlat_preset(dict);
2829                 }
2830         }
2831 }
2832
2833 static guint prefs_timeout_id = 0;
2834
2835 static gboolean
2836 delayed_store_prefs(gpointer data)
2837 {
2838         store_plist(prefsPlist, "preferences");
2839         prefs_timeout_id = 0;
2840         return FALSE;
2841 }
2842
2843 static void
2844 store_presets()
2845 {
2846         GValue *export;
2847
2848         export = ghb_value_dup(presetsPlist);
2849         export_xlat_presets(export);
2850         store_plist(export, "presets");
2851         ghb_value_free(export);
2852 }
2853
2854 static void
2855 store_prefs(void)
2856 {
2857         if (prefs_timeout_id != 0)
2858         {
2859                 GMainContext *mc;
2860                 GSource *source;
2861
2862                 mc = g_main_context_default();
2863                 source = g_main_context_find_source_by_id(mc, prefs_timeout_id);
2864                 if (source != NULL)
2865                         g_source_destroy(source);
2866         }
2867         prefs_timeout_id = g_timeout_add_seconds(1, (GSourceFunc)delayed_store_prefs, NULL);
2868 }
2869
2870 void
2871 ghb_presets_reload(signal_user_data_t *ud)
2872 {
2873         GValue *std_presets;
2874         gint count, ii;
2875         int *indices, len;
2876
2877         g_debug("ghb_presets_reload()\n");
2878         std_presets = ghb_resource_get("standard-presets");
2879         if (std_presets == NULL) return;
2880
2881         remove_std_presets(ud);
2882         indices = presets_find_default(presetsPlist, &len);
2883         if (indices)
2884         {
2885                 presets_clear_default(std_presets);
2886                 g_free(indices);
2887         }
2888         // Merge the keyfile contents into our presets
2889         count = ghb_array_len(std_presets);
2890         for (ii = count-1; ii >= 0; ii--)
2891         {
2892                 GValue *std_dict;
2893                 GValue *copy_dict;
2894                 gint indices = 0;
2895
2896                 std_dict = ghb_array_get_nth(std_presets, ii);
2897                 copy_dict = ghb_value_dup(std_dict);
2898                 ghb_dict_insert(copy_dict, g_strdup("PresetBuildNumber"), 
2899                                                 ghb_int64_value_new(hb_get_build(NULL)));
2900                 ghb_presets_insert(presetsPlist, copy_dict, &indices, 1);
2901                 presets_list_insert(ud, &indices, 1);
2902         }
2903         import_xlat_presets(presetsPlist);
2904         store_presets();
2905 }
2906
2907 static gboolean
2908 check_old_presets()
2909 {
2910         gint count, ii;
2911
2912         count = ghb_array_len(presetsPlist);
2913         for (ii = count-1; ii >= 0; ii--)
2914         {
2915                 GValue *dict;
2916                 GValue *type;
2917
2918                 dict = ghb_array_get_nth(presetsPlist, ii);
2919                 type = ghb_dict_lookup(dict, "Type");
2920                 if (type == NULL)
2921                         return TRUE;
2922         }
2923         return FALSE;
2924 }
2925
2926 static void
2927 replace_standard_presets()
2928 {
2929         GValue *std_presets;
2930         int *indices, len;
2931         gint count, ii;
2932
2933         count = ghb_array_len(presetsPlist);
2934         for (ii = count-1; ii >= 0; ii--)
2935         {
2936                 GValue *dict;
2937                 gint ptype;
2938
2939                 dict = ghb_array_get_nth(presetsPlist, ii);
2940                 ptype = ghb_value_int(preset_dict_get_value(dict, "Type"));
2941                 if (ptype == PRESETS_BUILTIN)
2942                 {
2943                         gint indices = 0;
2944                         ghb_presets_remove(presetsPlist, &indices, 1);
2945                 }
2946         }
2947
2948         std_presets = ghb_resource_get("standard-presets");
2949         if (std_presets == NULL) return;
2950
2951         indices = presets_find_default(presetsPlist, &len);
2952         if (indices)
2953         {
2954                 presets_clear_default(std_presets);
2955                 g_free(indices);
2956         }
2957         // Merge the keyfile contents into our presets
2958         count = ghb_array_len(std_presets);
2959         for (ii = count-1; ii >= 0; ii--)
2960         {
2961                 GValue *std_dict;
2962                 GValue *copy_dict;
2963                 gint indices = 0;
2964
2965                 std_dict = ghb_array_get_nth(std_presets, ii);
2966                 copy_dict = ghb_value_dup(std_dict);
2967                 ghb_dict_insert(copy_dict, g_strdup("PresetBuildNumber"), 
2968                                                 ghb_int64_value_new(hb_get_build(NULL)));
2969                 ghb_presets_insert(presetsPlist, copy_dict, &indices, 1);
2970         }
2971         import_xlat_presets(presetsPlist);
2972         store_presets();
2973 }
2974
2975 static void
2976 update_standard_presets(signal_user_data_t *ud)
2977 {
2978         gint count, ii;
2979
2980         count = ghb_array_len(presetsPlist);
2981         for (ii = count-1; ii >= 0; ii--)
2982         {
2983                 GValue *dict;
2984                 const GValue *gval;
2985                 gint64 build;
2986                 gint type;
2987
2988                 dict = ghb_array_get_nth(presetsPlist, ii);
2989                 gval = ghb_dict_lookup(dict, "Type");
2990                 if (gval == NULL)
2991                 {
2992                         // Old preset that doesn't have a Type
2993                         replace_standard_presets();
2994                         return;
2995                 }
2996                         
2997                 type = ghb_value_int(gval);
2998                 if (type == 0)
2999                 {
3000                         gval = ghb_dict_lookup(dict, "PresetBuildNumber");
3001                         if (gval == NULL)
3002                         {
3003                                 // Old preset that doesn't have a build number
3004                                 replace_standard_presets();
3005                                 return;
3006                         }
3007
3008                         build = ghb_value_int64(gval);
3009                         if (build != hb_get_build(NULL))
3010                         {
3011                                 // Build number does not match
3012                                 replace_standard_presets();
3013                                 return;
3014                         }
3015                 }
3016         }
3017         return;
3018 }
3019
3020 void
3021 ghb_presets_load(signal_user_data_t *ud)
3022 {
3023         presetsPlist = load_plist("presets");
3024         if (presetsPlist == NULL)
3025         {
3026                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
3027                 import_xlat_presets(presetsPlist);
3028                 store_presets();
3029         }
3030         else if (G_VALUE_TYPE(presetsPlist) == ghb_dict_get_type())
3031         { // Presets is older dictionary format. Convert to array
3032                 ghb_value_free(presetsPlist);
3033                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
3034                 import_xlat_presets(presetsPlist);
3035                 store_presets();
3036         }
3037         else if (check_old_presets())
3038         {
3039                 ghb_value_free(presetsPlist);
3040                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
3041                 import_xlat_presets(presetsPlist);
3042                 store_presets();
3043         }
3044         update_standard_presets(ud);
3045         import_xlat_presets(presetsPlist);
3046 }
3047
3048 static void
3049 settings_save(signal_user_data_t *ud, const GValue *path)
3050 {
3051         GValue *dict, *internal;
3052         GHashTableIter iter;
3053         gchar *key;
3054         GValue *value;
3055         gboolean autoscale;
3056         gint *indices, len, count;
3057         gint *def_indices, def_len;
3058         const gchar *name;
3059         gboolean replace = FALSE;
3060
3061         g_debug("settings_save");
3062         if (internalPlist == NULL) return;
3063         count = ghb_array_len(path);
3064         name = g_value_get_string(ghb_array_get_nth(path, count-1));
3065         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
3066         if (indices)
3067         {
3068                 if (ghb_presets_get_folder(presetsPlist, indices, len))
3069                 {
3070                         gchar *message;
3071                         message = g_strdup_printf(
3072                                                 "%s: Folder already exists.\n"
3073                                                 "You can not replace it with a preset.",
3074                                                 name);
3075                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3076                         g_free(message);
3077                         return;
3078                 }
3079                 dict = ghb_dict_value_new();
3080                 ghb_presets_replace(presetsPlist, dict, indices, len);
3081                 replace = TRUE;
3082         }
3083         else
3084         {
3085                 indices = presets_find_pos(path, PRESETS_CUSTOM, &len);
3086                 if (indices)
3087                 {
3088                         dict = ghb_dict_value_new();
3089                         ghb_presets_insert(presetsPlist, dict, indices, len);
3090                 }
3091                 else
3092                 {
3093                         g_warning("failed to find insert path");
3094                         return;
3095                 }
3096         }
3097         current_preset = dict;
3098         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
3099         ghb_settings_set_int64(ud->settings, "Type", PRESETS_CUSTOM);
3100         ghb_settings_set_int64(ud->settings, "PresetBuildNumber", hb_get_build(NULL));
3101
3102         internal = plist_get_dict(internalPlist, "Presets");
3103         ghb_dict_iter_init(&iter, internal);
3104         // middle (void*) cast prevents gcc warning "defreferencing type-punned
3105         // pointer will break strict-aliasing rules"
3106         while (g_hash_table_iter_next(
3107                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
3108         {
3109                 const GValue *gval;
3110                 gchar *key2;
3111
3112                 key2 = key;
3113                 if (!autoscale)
3114                 {
3115                         if (strcmp(key, "PictureWidth") == 0)
3116                         {
3117                                 key2 = "scale_width";
3118                         }
3119                         else if (strcmp(key, "PictureHeight") == 0)
3120                         {
3121                                 key2 = "scale_height";
3122                         }
3123                 }
3124                 gval = ghb_settings_get_value(ud->settings, key2);
3125                 if (gval == NULL)
3126                 {
3127                         continue;
3128                 }
3129                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
3130         }
3131         internal = plist_get_dict(internalPlist, "XlatPresets");
3132         ghb_dict_iter_init(&iter, internal);
3133         // middle (void*) cast prevents gcc warning "defreferencing type-punned
3134         // pointer will break strict-aliasing rules"
3135         while (g_hash_table_iter_next(
3136                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
3137         {
3138                 const GValue *gval;
3139
3140                 gval = ghb_settings_get_value(ud->settings, key);
3141                 if (gval == NULL)
3142                 {
3143                         continue;
3144                 }
3145                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
3146         }
3147         ghb_dict_insert(dict, g_strdup("PresetName"), ghb_string_value_new(name));
3148         if (replace)
3149         {
3150                 def_indices = presets_find_default(presetsPlist, &def_len);
3151                 if (def_indices != NULL && 
3152                         preset_path_cmp(indices, len, def_indices, def_len) != 0)
3153                 {
3154                         ghb_dict_insert(dict, g_strdup("Default"), 
3155                                                         ghb_boolean_value_new(FALSE));
3156                 }
3157                 presets_list_update_item(ud, indices, len, FALSE);
3158         }
3159         else
3160         {
3161                 ghb_dict_insert(dict, g_strdup("Default"), 
3162                                                 ghb_boolean_value_new(FALSE));
3163                 presets_list_insert(ud, indices, len);
3164         }
3165         store_presets();
3166         ud->dont_clear_presets = TRUE;
3167         // Make the new preset the selected item
3168         ghb_select_preset2(ud->builder, indices, len);
3169         g_free(indices);
3170         ud->dont_clear_presets = FALSE;
3171         return;
3172 }
3173
3174 static void
3175 folder_save(signal_user_data_t *ud, const GValue *path)
3176 {
3177         GValue *dict, *folder;
3178         gint *indices, len, count;
3179         const gchar *name;
3180
3181         count = ghb_array_len(path);
3182         name = g_value_get_string(ghb_array_get_nth(path, count-1));
3183         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
3184         if (indices)
3185         {
3186                 if (!ghb_presets_get_folder(presetsPlist, indices, len))
3187                 {
3188                         gchar *message;
3189                         message = g_strdup_printf(
3190                                                 "%s: Preset already exists.\n"
3191                                                 "You can not replace it with a folder.",
3192                                                 name);
3193                         ghb_message_dialog(GTK_MESSAGE_ERROR, message, "Cancel", NULL);
3194                         g_free(message);
3195                         g_free(indices);
3196                         return;
3197                 }
3198                 // Already exists, update its description
3199                 dict = presets_get_dict(presetsPlist, indices, len);
3200                 ghb_dict_insert(dict, g_strdup("PresetDescription"), 
3201                         ghb_value_dup(preset_dict_get_value(
3202                                 ud->settings, "PresetDescription")));
3203                 presets_list_update_item(ud, indices, len, FALSE);
3204                 g_free(indices);
3205                 store_presets();
3206                 return;
3207         }
3208         else
3209         {
3210                 indices = presets_find_pos(path, PRESETS_CUSTOM, &len);
3211                 if (indices)
3212                 {
3213                         dict = ghb_dict_value_new();
3214                         ghb_presets_insert(presetsPlist, dict, indices, len);
3215                 }
3216                 else
3217                 {
3218                         g_warning("failed to find insert path");
3219                         return;
3220                 }
3221         }
3222         ghb_dict_insert(dict, g_strdup("PresetDescription"), 
3223                 ghb_value_dup(preset_dict_get_value(
3224                         ud->settings, "PresetDescription")));
3225         ghb_dict_insert(dict, g_strdup("PresetName"), ghb_string_value_new(name));
3226         folder = ghb_array_value_new(8);
3227         ghb_dict_insert(dict, g_strdup("ChildrenArray"), folder);
3228         ghb_dict_insert(dict, g_strdup("Type"),
3229                                                         ghb_int64_value_new(PRESETS_CUSTOM));
3230         ghb_dict_insert(dict, g_strdup("Folder"), ghb_boolean_value_new(TRUE));
3231
3232         presets_list_insert(ud, indices, len);
3233         g_free(indices);
3234         store_presets();
3235         return;
3236 }
3237
3238 void
3239 ghb_presets_list_default(signal_user_data_t *ud)
3240 {
3241         GtkTreeView *treeview;
3242         GtkTreePath *treepath;
3243         GtkTreeIter iter;
3244         GtkTreeStore *store;
3245         gint *indices, len;
3246         
3247         g_debug("ghb_presets_list_default ()");
3248         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
3249         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
3250         indices = presets_find_default(presetsPlist, &len);
3251         if (indices == NULL) return;
3252         treepath = ghb_tree_path_new_from_indices(indices, len);
3253         if (treepath)
3254         {
3255                 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath))
3256                 {
3257                         gtk_tree_store_set(store, &iter, 
3258                                                 1, 800, 
3259                                                 2, 2 ,
3260                                                 -1);
3261                 }
3262                 gtk_tree_path_free(treepath);
3263         }
3264         g_free(indices);
3265 }
3266
3267 void
3268 ghb_presets_list_clear_default(signal_user_data_t *ud)
3269 {
3270         GtkTreeView *treeview;
3271         GtkTreePath *treepath;
3272         GtkTreeIter iter;
3273         GtkTreeStore *store;
3274         gint *indices, len;
3275         
3276         g_debug("ghb_presets_list_clear_default ()");
3277         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
3278         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
3279         indices = presets_find_default(presetsPlist, &len);
3280         if (indices == NULL) return;
3281         treepath = ghb_tree_path_new_from_indices(indices, len);
3282         if (treepath)
3283         {
3284                 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath))
3285                 {
3286                         gtk_tree_store_set(store, &iter, 
3287                                                 1, 400, 
3288                                                 2, 0 ,
3289                                                 -1);
3290                 }
3291                 gtk_tree_path_free(treepath);
3292         }
3293         g_free(indices);
3294 }
3295
3296 static void
3297 update_audio_presets(signal_user_data_t *ud)
3298 {
3299         g_debug("update_audio_presets");
3300         const GValue *audio_list;
3301
3302         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
3303         ghb_settings_set_value(ud->settings, "AudioList", audio_list);
3304 }
3305
3306 static void
3307 update_subtitle_presets(signal_user_data_t *ud)
3308 {
3309         g_debug("update_subtitle_presets");
3310         const GValue *subtitle_list, *subtitle;
3311         GValue *slist, *dict;
3312         gint count, ii, source;
3313
3314         subtitle_list = ghb_settings_get_value(ud->settings, "subtitle_list");
3315         slist = ghb_array_value_new(8);
3316         count = ghb_array_len(subtitle_list);
3317         for (ii = 0; ii < count; ii++)
3318         {
3319                 subtitle = ghb_array_get_nth(subtitle_list, ii);
3320                 source = ghb_settings_get_int(subtitle, "SubtitleSource");
3321                 if (source != SRTSUB)
3322                 {
3323                         dict = ghb_value_dup(subtitle);
3324                         ghb_array_append(slist, dict);
3325                 }
3326         }
3327         ghb_settings_take_value(ud->settings, "SubtitleList", slist);
3328 }
3329
3330 G_MODULE_EXPORT void
3331 presets_menu_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3332 {
3333         GtkMenu *menu;
3334
3335         menu = GTK_MENU(GHB_WIDGET(ud->builder, "presets_menu"));
3336         gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 1, 
3337                                         gtk_get_current_event_time());
3338 }
3339
3340 G_MODULE_EXPORT void
3341 preset_import_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3342 {
3343         GtkWidget *dialog;
3344         GtkResponseType response;
3345         gchar *exportDir;
3346         gchar *filename;
3347         GtkFileFilter *filter;
3348
3349         g_debug("preset_import_clicked_cb ()");
3350
3351         dialog = gtk_file_chooser_dialog_new("Import Preset", NULL,
3352                                 GTK_FILE_CHOOSER_ACTION_OPEN,
3353                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3354                                 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
3355                                 NULL);
3356
3357         filter = gtk_file_filter_new();
3358         gtk_file_filter_set_name(filter, "All (*)");
3359         gtk_file_filter_add_pattern(filter, "*");
3360         gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
3361
3362         filter = gtk_file_filter_new();
3363         gtk_file_filter_set_name(filter, "Presets (*.plist)");
3364         gtk_file_filter_add_pattern(filter, "*.plist");
3365         gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
3366         gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
3367
3368         exportDir = ghb_settings_get_string(ud->settings, "ExportDirectory");
3369         if (exportDir == NULL || exportDir[0] == '\0')
3370         {
3371                 exportDir = g_strdup(".");
3372         }
3373         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), exportDir);
3374         g_free(exportDir);
3375
3376         response = gtk_dialog_run(GTK_DIALOG(dialog));
3377         gtk_widget_hide(dialog);
3378         if (response == GTK_RESPONSE_ACCEPT)
3379         {
3380                 GValue *dict, *array;
3381                 gchar  *dir;
3382                 gint count, ii;
3383
3384                 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
3385
3386                 // import the preset
3387                 if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR))
3388                 {
3389                         gtk_widget_destroy(dialog);
3390                         g_free(filename);
3391                         return;
3392                 }
3393                 array = ghb_plist_parse_file(filename);
3394
3395                 import_xlat_presets(array);
3396                 presets_clear_default(array);
3397                 presets_customize(array);
3398
3399                 count = ghb_array_len(array);
3400                 for (ii = 0; ii < count; ii++)
3401                 {
3402                         GValue *path, *name;
3403                         gint *indices, len;
3404                         gint index = 1;
3405
3406                         dict = ghb_array_get_nth(array, ii);
3407                         path = ghb_array_value_new(1);
3408                         name = ghb_value_dup(ghb_dict_lookup(dict, "PresetName"));
3409                         ghb_array_append(path, name);
3410                         indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
3411                         // Modify the preset name till we make it unique
3412                         while (indices != NULL)
3413                         {
3414                                 gchar *str = ghb_value_string(name);
3415
3416                                 ghb_value_free(path);
3417                                 g_free(indices);
3418
3419                                 str = g_strdup_printf("%s %d", str, index);
3420                                 path = ghb_array_value_new(1);
3421                                 name = ghb_string_value_new(str);
3422                                 ghb_array_append(path, name);
3423                                 g_free(str);
3424
3425                                 index++;
3426                                 indices = ghb_preset_indices_from_path(presetsPlist, path, &len);
3427                         }
3428                         ghb_dict_insert(dict, g_strdup("PresetName"), ghb_value_dup(name));
3429                         indices = presets_find_pos(path, PRESETS_CUSTOM, &len);
3430                         ghb_presets_insert(presetsPlist, ghb_value_dup(dict), indices, len);
3431                         presets_list_insert(ud, indices, len);
3432                         ghb_value_free(path);
3433                 }
3434                 ghb_value_free(array);
3435
3436                 exportDir = ghb_settings_get_string(ud->settings, "ExportDirectory");
3437                 dir = g_path_get_dirname(filename);
3438                 if (strcmp(dir, exportDir) != 0)
3439                 {
3440                         ghb_settings_set_string(ud->settings, "ExportDirectory", dir);
3441                         ghb_pref_save(ud->settings, "ExportDirectory");
3442                 }
3443                 g_free(filename);
3444                 g_free(exportDir);
3445                 g_free(dir);
3446                 store_presets();
3447         }
3448         gtk_widget_destroy(dialog);
3449 }
3450
3451 G_MODULE_EXPORT void
3452 preset_export_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3453 {
3454         GtkWidget *dialog;
3455         GtkResponseType response;
3456         GValue *preset;
3457         const gchar *name = "";
3458         gint count, *indices, len;
3459         gchar *exportDir;
3460         gchar *filename;
3461
3462         g_debug("preset_export_clicked_cb ()");
3463         preset = ghb_settings_get_value (ud->settings, "preset_selection");
3464         if (preset == NULL)
3465                 return;
3466
3467         count = ghb_array_len(preset);
3468         if (count <= 0)
3469                 return;
3470
3471         name = g_value_get_string(ghb_array_get_nth(preset, count-1));
3472
3473         dialog = gtk_file_chooser_dialog_new("Export Preset", NULL,
3474                                 GTK_FILE_CHOOSER_ACTION_SAVE,
3475                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
3476                                 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
3477                                 NULL);
3478
3479         exportDir = ghb_settings_get_string(ud->settings, "ExportDirectory");
3480         if (exportDir == NULL || exportDir[0] == '\0')
3481         {
3482                 exportDir = g_strdup(".");
3483         }
3484         filename = g_strdup_printf("%s.plist", name);
3485         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), exportDir);
3486         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename);
3487         g_free(filename);
3488         g_free(exportDir);
3489
3490         indices = ghb_preset_indices_from_path(presetsPlist, preset, &len);
3491         if (indices == NULL)
3492                 return;
3493
3494         response = gtk_dialog_run(GTK_DIALOG(dialog));
3495         gtk_widget_hide(dialog);
3496         if (response == GTK_RESPONSE_ACCEPT)
3497         {
3498                 GValue *export, *dict, *array;
3499                 FILE *file;
3500                 gchar  *dir;
3501
3502                 filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
3503
3504                 // export the preset
3505                 dict = presets_get_dict(presetsPlist, indices, len);
3506
3507                 export = ghb_value_dup(dict);
3508                 array = ghb_array_value_new(1);
3509                 ghb_array_append(array, export);
3510                 presets_clear_default(array);
3511                 presets_customize(array);
3512                 export_xlat_presets(array);
3513
3514                 file = g_fopen(filename, "w");
3515                 if (file != NULL)
3516                 {
3517                         ghb_plist_write(file, array);
3518                         fclose(file);
3519                 }
3520                 ghb_value_free(array);
3521
3522                 exportDir = ghb_settings_get_string(ud->settings, "ExportDirectory");
3523                 dir = g_path_get_dirname(filename);
3524                 if (strcmp(dir, exportDir) != 0)
3525                 {
3526                         ghb_settings_set_string(ud->settings, "ExportDirectory", dir);
3527                         ghb_pref_save(ud->settings, "ExportDirectory");
3528                 }
3529                 g_free(exportDir);
3530                 g_free(dir);
3531                 g_free(filename);
3532         }
3533         gtk_widget_destroy(dialog);
3534         g_free(indices);
3535 }
3536
3537 G_MODULE_EXPORT void
3538 presets_new_folder_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3539 {
3540         GtkWidget *dialog;
3541         GtkEntry *entry;
3542         GtkTextView *desc;
3543         GtkResponseType response;
3544         GValue *preset, *dict;
3545         const gchar *name = "";
3546         const gchar *description = "";
3547         gint count, *indices, len;
3548
3549         g_debug("presets_save_clicked_cb ()");
3550         preset = ghb_settings_get_value (ud->settings, "preset_selection");
3551
3552         count = ghb_array_len(preset);
3553         if (count > 0)
3554                 name = g_value_get_string(ghb_array_get_nth(preset, count-1));
3555         else
3556                 count = 1;
3557
3558         indices = ghb_preset_indices_from_path(presetsPlist, preset, &len);
3559         dict = presets_get_dict(presetsPlist, indices, len);
3560         if (dict != NULL)
3561         {
3562                 description = g_value_get_string(
3563                                                         ghb_dict_lookup(dict, "PresetDescription"));
3564                 ghb_ui_update(ud, "PresetDescription", ghb_string_value(description));
3565         }
3566
3567         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "PresetDescription"));
3568         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
3569         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "PresetName"));
3570         gtk_entry_set_text(entry, name);
3571         response = gtk_dialog_run(GTK_DIALOG(dialog));
3572         gtk_widget_hide(dialog);
3573         if (response == GTK_RESPONSE_OK)
3574         {
3575                 // save the preset
3576                 const gchar *name = gtk_entry_get_text(entry);
3577                 GValue *dest;
3578
3579                 if (count > MAX_NESTED_PRESET-1)
3580                         count = MAX_NESTED_PRESET-1;
3581
3582                 dest = ghb_array_value_new(MAX_NESTED_PRESET);
3583                 if (indices != NULL)
3584                 {
3585                         gint ptype;
3586
3587                         ptype = ghb_presets_get_type(presetsPlist, indices, len);
3588                         if (ptype == PRESETS_CUSTOM)
3589                         {
3590                                 ghb_array_copy(dest, preset, count-1);
3591                         }
3592                 }
3593                 ghb_array_append(dest, ghb_string_value_new(name));
3594                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
3595                 folder_save(ud, dest);
3596                 ghb_value_free(dest);
3597         }
3598         if (indices != NULL)
3599                 g_free(indices);
3600 }
3601
3602 G_MODULE_EXPORT void
3603 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3604 {
3605         GtkWidget *dialog;
3606         GtkEntry *entry;
3607         GtkTextView *desc;
3608         GtkResponseType response;
3609         GValue *preset;
3610         const gchar *name = "";
3611         gint count, *indices, len;
3612
3613         g_debug("presets_save_clicked_cb ()");
3614         preset = ghb_settings_get_value (ud->settings, "preset_selection");
3615
3616         count = ghb_array_len(preset);
3617         if (count > 0)
3618                 name = g_value_get_string(ghb_array_get_nth(preset, count-1));
3619         else
3620                 count = 1;
3621
3622         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "PresetDescription"));
3623         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
3624         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "PresetName"));
3625         gtk_entry_set_text(entry, name);
3626         response = gtk_dialog_run(GTK_DIALOG(dialog));
3627         gtk_widget_hide(dialog);
3628         if (response == GTK_RESPONSE_OK)
3629         {
3630                 // save the preset
3631                 const gchar *name = gtk_entry_get_text(entry);
3632                 GValue *dest;
3633
3634                 dest = ghb_array_value_new(MAX_NESTED_PRESET);
3635                 indices = ghb_preset_indices_from_path(presetsPlist, preset, &len);
3636                 if (indices)
3637                 {
3638                         gint ptype;
3639
3640                         ptype = ghb_presets_get_type(presetsPlist, indices, len);
3641                         if (ptype == PRESETS_CUSTOM)
3642                         {
3643                                 ghb_array_copy(dest, preset, count-1);
3644                         }
3645                         g_free(indices);
3646                 }
3647                 ghb_array_append(dest, ghb_string_value_new(name));
3648
3649                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
3650
3651                 // Construct the audio settings presets from the current audio list
3652                 update_audio_presets(ud);
3653                 update_subtitle_presets(ud);
3654                 settings_save(ud, dest);
3655                 ghb_value_free(dest);
3656         }
3657 }
3658
3659 G_MODULE_EXPORT void
3660 preset_type_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
3661 {
3662         ghb_widget_to_setting(ud->settings, widget);
3663 }
3664
3665 G_MODULE_EXPORT void
3666 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3667 {
3668         GValue *preset;
3669
3670         g_debug("presets_restore_clicked_cb ()");
3671         // Reload only the standard presets
3672         ghb_presets_reload(ud);
3673         // Updating the presets list shuffles things around
3674         // need to make sure the proper preset is selected
3675         preset = ghb_settings_get_value (ud->settings, "preset");
3676         ghb_select_preset(ud->builder, preset);
3677 }
3678
3679 G_MODULE_EXPORT void
3680 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
3681 {
3682         GtkTreeView *treeview;
3683         GtkTreeSelection *selection;
3684         GtkTreeModel *store;
3685         GtkTreeIter iter;
3686         gchar *preset;
3687         GtkResponseType response;
3688
3689         g_debug("presets_remove_clicked_cb ()");
3690         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
3691         selection = gtk_tree_view_get_selection (treeview);
3692         if (gtk_tree_selection_get_selected(selection, &store, &iter))
3693         {
3694                 GtkWidget *dialog;
3695                 GtkTreePath *path;
3696                 gint *indices, len;
3697                 gboolean folder;
3698
3699                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
3700                 path = gtk_tree_model_get_path(store, &iter);
3701                 indices = gtk_tree_path_get_indices(path);
3702                 len = gtk_tree_path_get_depth(path);
3703
3704                 folder = ghb_presets_get_folder(presetsPlist, indices, len);
3705                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
3706                                                         GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
3707                                                         "Confirm deletion of %s:\n\n%s", 
3708                                                         folder ? "folder" : "preset",
3709                                                         preset);
3710                 response = gtk_dialog_run(GTK_DIALOG(dialog));
3711                 gtk_widget_destroy (dialog);
3712                 if (response == GTK_RESPONSE_YES)
3713                 {
3714                         GtkTreeIter nextIter = iter;
3715                         gboolean valid = TRUE;
3716                         if (!gtk_tree_model_iter_next(store, &nextIter))
3717                         {
3718                                 if (!gtk_tree_model_iter_parent(store, &nextIter, &iter))
3719                                 {
3720                                         valid = FALSE;
3721                                 }
3722                         }
3723                         // Remove the selected item
3724                         // First unselect it so that selecting the new item works properly
3725                         gtk_tree_selection_unselect_iter (selection, &iter);
3726                         if (ghb_presets_remove(presetsPlist, indices, len))
3727                         {
3728                                 store_presets();
3729                                 presets_list_remove(ud, indices, len);
3730                         }
3731                         if (!valid)
3732                                 valid = gtk_tree_model_get_iter_first(store, &nextIter);
3733                         if (valid)
3734                         {
3735                                 gtk_tree_path_free(path);
3736                                 path = gtk_tree_model_get_path(store, &nextIter);
3737                                 indices = gtk_tree_path_get_indices(path);
3738                                 len = gtk_tree_path_get_depth(path);
3739                                 ghb_select_preset2(ud->builder, indices, len);
3740                         }
3741                 }
3742                 g_free(preset);
3743                 gtk_tree_path_free(path);
3744         }
3745 }
3746
3747 // controls where valid drop locations are
3748 G_MODULE_EXPORT gboolean
3749 presets_drag_motion_cb(
3750         GtkTreeView *tv,
3751         GdkDragContext *ctx,
3752         gint x,
3753         gint y,
3754         guint time,
3755         signal_user_data_t *ud)
3756 {
3757         GtkTreePath *path = NULL;
3758         GtkTreeViewDropPosition drop_pos;
3759         gint *indices, len;
3760         GtkTreeIter iter;
3761         GtkTreeView *srctv;
3762         GtkTreeModel *model;
3763         GtkTreeSelection *select;
3764         gint src_ptype, dst_ptype;
3765         gboolean src_folder, dst_folder;
3766         GValue *preset;
3767         gint tree_depth, ii;
3768         GtkWidget *widget;
3769
3770         widget = gtk_drag_get_source_widget(ctx);
3771         if (widget == NULL || widget != GTK_WIDGET(tv))
3772                 return TRUE;
3773
3774         // Get the type of the object being dragged
3775         srctv = GTK_TREE_VIEW(gtk_drag_get_source_widget(ctx));
3776         select = gtk_tree_view_get_selection (srctv);
3777         gtk_tree_selection_get_selected (select, &model, &iter);
3778         path = gtk_tree_model_get_path (model, &iter);
3779         indices = gtk_tree_path_get_indices(path);
3780         len = gtk_tree_path_get_depth(path);
3781
3782         preset = presets_get_dict(presetsPlist, indices, len);
3783         tree_depth = preset_tree_depth(preset);
3784
3785         src_ptype = ghb_presets_get_type(presetsPlist, indices, len);
3786         src_folder = ghb_presets_get_folder(presetsPlist, indices, len);
3787         gtk_tree_path_free(path);
3788
3789         if (src_folder && tree_depth == 1)
3790                 tree_depth = 2;
3791
3792         // The rest checks that the destination is a valid position
3793         // in the list.
3794         gtk_tree_view_get_dest_row_at_pos (tv, x, y, &path, &drop_pos);
3795         if (path == NULL)
3796         {
3797                 gdk_drag_status(ctx, 0, time);
3798                 return TRUE;
3799         }
3800         // Don't allow repositioning of builtin presets
3801         if (src_ptype != PRESETS_CUSTOM)
3802         {
3803                 gdk_drag_status(ctx, 0, time);
3804                 return TRUE;
3805         }
3806
3807         len = gtk_tree_path_get_depth(path);
3808         if (len+tree_depth-1 >= MAX_NESTED_PRESET)
3809         {
3810                 if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
3811                         drop_pos = GTK_TREE_VIEW_DROP_BEFORE;
3812                 if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3813                         drop_pos = GTK_TREE_VIEW_DROP_AFTER;
3814         }
3815         for (ii = len+tree_depth-1; ii > MAX_NESTED_PRESET; ii--)
3816                 gtk_tree_path_up(path);
3817         indices = gtk_tree_path_get_indices(path);
3818         len = gtk_tree_path_get_depth(path);
3819         dst_ptype = ghb_presets_get_type(presetsPlist, indices, len);
3820         dst_folder = ghb_presets_get_folder(presetsPlist, indices, len);
3821         // Don't allow mixing custom presets in the builtins
3822         if (dst_ptype != PRESETS_CUSTOM)
3823         {
3824                 gdk_drag_status(ctx, 0, time);
3825                 return TRUE;
3826         }
3827
3828         // Only allow *drop into* for folders
3829         if (!dst_folder)
3830         { 
3831                 if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
3832                         drop_pos = GTK_TREE_VIEW_DROP_BEFORE;
3833                 if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3834                         drop_pos = GTK_TREE_VIEW_DROP_AFTER;
3835         }
3836
3837         len = gtk_tree_path_get_depth(path);
3838         gtk_tree_view_set_drag_dest_row(tv, path, drop_pos);
3839         gtk_tree_path_free(path);
3840         gdk_drag_status(ctx, GDK_ACTION_MOVE, time);
3841         return TRUE;
3842 }
3843
3844 G_MODULE_EXPORT void 
3845 presets_drag_cb(
3846         GtkTreeView *dstwidget, 
3847         GdkDragContext *dc, 
3848         gint x, gint y, 
3849         GtkSelectionData *selection_data, 
3850         guint info, guint t, 
3851         signal_user_data_t *ud)
3852 {
3853         GtkTreePath *path = NULL;
3854         GtkTreeViewDropPosition drop_pos;
3855         GtkTreeIter dstiter, srciter;
3856         gint *dst_indices, dst_len, *src_indices, src_len;
3857         gint src_ptype;
3858         gboolean src_folder, dst_folder;
3859         
3860         GtkTreeModel *dstmodel = gtk_tree_view_get_model(dstwidget);
3861                         
3862         g_debug("preset_drag_cb ()");
3863         // This doesn't work here for some reason...
3864         // gtk_tree_view_get_drag_dest_row(dstwidget, &path, &drop_pos);
3865         gtk_tree_view_get_dest_row_at_pos (dstwidget, x, y, &path, &drop_pos);
3866         // This little hack is needed because attempting to drop after
3867         // the last item gives us no path or drop_pos.
3868         if (path == NULL)
3869         {
3870                 gint n_children;
3871
3872                 n_children = gtk_tree_model_iter_n_children(dstmodel, NULL);
3873                 if (n_children)
3874                 {
3875                         drop_pos = GTK_TREE_VIEW_DROP_AFTER;
3876                         path = gtk_tree_path_new_from_indices(n_children-1, -1);
3877                 }
3878                 else
3879                 {
3880                         drop_pos = GTK_TREE_VIEW_DROP_BEFORE;
3881                         path = gtk_tree_path_new_from_indices(0, -1);
3882                 }
3883         }
3884         if (path)
3885         {
3886                 GtkTreeView *srcwidget;
3887                 GtkTreeModel *srcmodel;
3888                 GtkTreeSelection *select;
3889                 GtkTreePath *srcpath = NULL;
3890                 GValue *preset;
3891                 gint tree_depth, ii;
3892
3893                 srcwidget = GTK_TREE_VIEW(gtk_drag_get_source_widget(dc));
3894                 select = gtk_tree_view_get_selection (srcwidget);
3895                 gtk_tree_selection_get_selected (select, &srcmodel, &srciter);
3896
3897                 srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
3898                 src_indices = gtk_tree_path_get_indices(srcpath);
3899                 src_len = gtk_tree_path_get_depth(srcpath);
3900                 src_ptype = ghb_presets_get_type(presetsPlist, src_indices, src_len);
3901                 src_folder = ghb_presets_get_folder(presetsPlist, src_indices, src_len);
3902                 preset = ghb_value_dup(
3903                                         presets_get_dict(presetsPlist, src_indices, src_len));
3904                 gtk_tree_path_free(srcpath);
3905
3906                 // Don't allow repositioning of builtin presets
3907                 if (src_ptype != PRESETS_CUSTOM)
3908                         return;
3909
3910                 tree_depth = preset_tree_depth(preset);
3911                 if (src_folder && tree_depth == 1)
3912                         tree_depth = 2;
3913
3914                 dst_len = gtk_tree_path_get_depth(path);
3915                 if (dst_len+tree_depth-1 >= MAX_NESTED_PRESET)
3916                 {
3917                         if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
3918                                 drop_pos = GTK_TREE_VIEW_DROP_BEFORE;
3919                         if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3920                                 drop_pos = GTK_TREE_VIEW_DROP_AFTER;
3921                 }
3922
3923                 for (ii = dst_len+tree_depth-1; ii > MAX_NESTED_PRESET; ii--)
3924                         gtk_tree_path_up(path);
3925                 dst_indices = gtk_tree_path_get_indices(path);
3926                 dst_len = gtk_tree_path_get_depth(path);
3927                 dst_folder = ghb_presets_get_folder(presetsPlist, dst_indices, dst_len);
3928                 // Only allow *drop into* for folders
3929                 if (!dst_folder)
3930                 { 
3931                         if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
3932                                 drop_pos = GTK_TREE_VIEW_DROP_BEFORE;
3933                         if (drop_pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
3934                                 drop_pos = GTK_TREE_VIEW_DROP_AFTER;
3935                 }
3936                 if (gtk_tree_model_get_iter (dstmodel, &dstiter, path))
3937                 {
3938                         GtkTreeIter iter;
3939                         GtkTreePath *dstpath = NULL;
3940
3941                         switch (drop_pos)
3942                         {
3943                                 case GTK_TREE_VIEW_DROP_BEFORE:
3944                                         gtk_tree_store_insert_before(GTK_TREE_STORE (dstmodel), 
3945                                                                                                 &iter, NULL, &dstiter);
3946                                         break;
3947
3948                                 case GTK_TREE_VIEW_DROP_INTO_OR_BEFORE:
3949                                         gtk_tree_store_insert(GTK_TREE_STORE (dstmodel), 
3950                                                                                                 &iter, &dstiter, 0);
3951                                         break;
3952
3953                                 case GTK_TREE_VIEW_DROP_AFTER:
3954                                         gtk_tree_store_insert_after(GTK_TREE_STORE (dstmodel), 
3955                                                                                                 &iter, NULL, &dstiter);
3956                                         break;
3957
3958                                 case GTK_TREE_VIEW_DROP_INTO_OR_AFTER:
3959                                         gtk_tree_store_insert_after(GTK_TREE_STORE (dstmodel), 
3960                                                                                                 &iter, &dstiter, 0);
3961                                         break;
3962
3963                                 default:
3964                                         break;
3965                         }
3966
3967                         dstpath = gtk_tree_model_get_path (dstmodel, &iter);
3968                         dst_indices = gtk_tree_path_get_indices(dstpath);
3969                         dst_len = gtk_tree_path_get_depth(dstpath);
3970                         ghb_presets_insert(presetsPlist, preset, dst_indices, dst_len);
3971                         gtk_tree_path_free(dstpath);
3972
3973                         srcpath = gtk_tree_model_get_path (srcmodel, &srciter);
3974                         src_indices = gtk_tree_path_get_indices(srcpath);
3975                         src_len = gtk_tree_path_get_depth(srcpath);
3976                         ghb_presets_remove(presetsPlist, src_indices, src_len);
3977                         gtk_tree_path_free(srcpath);
3978
3979                         gtk_tree_store_remove (GTK_TREE_STORE (srcmodel), &srciter);
3980
3981                         dstpath = gtk_tree_model_get_path (dstmodel, &iter);
3982                         dst_indices = gtk_tree_path_get_indices(dstpath);
3983                         dst_len = gtk_tree_path_get_depth(dstpath);
3984                         presets_list_update_item(ud, dst_indices, dst_len, TRUE);
3985                         gtk_tree_path_free(dstpath);
3986
3987                         store_presets();
3988                 }
3989                 gtk_tree_path_free(path);
3990         }
3991 }
3992
3993 void
3994 presets_row_expanded_cb(
3995         GtkTreeView *treeview, 
3996         GtkTreeIter *iter, 
3997         GtkTreePath *path, 
3998         signal_user_data_t *ud)
3999 {
4000         gint *indices, len;
4001         gboolean expanded, folder;
4002         GValue *dict;
4003
4004         expanded = gtk_tree_view_row_expanded(treeview, path);
4005         indices = gtk_tree_path_get_indices(path);
4006         len = gtk_tree_path_get_depth(path);
4007         dict = presets_get_dict(presetsPlist, indices, len);
4008         if (preset_folder_is_open(dict))
4009         {
4010                 if (expanded)
4011                         return;
4012         }
4013         else if (!expanded)
4014         {
4015                 return;
4016         }
4017         folder = ghb_presets_get_folder(presetsPlist, indices, len);
4018         if (folder)
4019         {
4020                 presets_set_folder_open(expanded, indices, len);
4021         }
4022
4023         // Collapsing parent folder collapses all children
4024         if (!expanded)
4025         {
4026                 GValue *presets = NULL;
4027                 gint *more_indices, count, ii;
4028
4029                 more_indices = g_malloc((len+1)*sizeof(gint));
4030                 memcpy(more_indices, indices, len*sizeof(gint));
4031
4032                 presets = presets_get_folder(presetsPlist, indices, len);
4033                 count = ghb_array_len(presets);
4034                 for (ii = 0; ii < count; ii++)
4035                 {
4036                         dict = ghb_array_get_nth(presets, ii);
4037                         folder = ghb_preset_folder(dict);
4038                         if (folder)
4039                         {
4040                                 more_indices[len] = ii;
4041                                 presets_set_folder_open(expanded, more_indices, len+1);
4042                         }
4043                 }
4044                 g_free(more_indices);
4045         }
4046         store_presets();
4047 }
4048
4049 static void
4050 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
4051 {
4052         GtkWidget *widget;
4053
4054         ghb_ui_update(ud, "scale_width", 
4055                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
4056         // If anamorphic or keep_aspect, the hight will be automatically calculated
4057         gboolean keep_aspect;
4058         gint pic_par;
4059         keep_aspect = ghb_settings_get_boolean(ud->settings, "PictureKeepRatio");
4060         pic_par = ghb_settings_combo_int(ud->settings, "PicturePAR");
4061         if (!(keep_aspect || pic_par) || pic_par == 3)
4062         {
4063                 ghb_ui_update(ud, "scale_height", 
4064                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
4065         }
4066
4067         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
4068         // you pass it a cropped width or height == 0.
4069         gint bound;
4070         bound = tinfo->height / 2 - 2;
4071         widget = GHB_WIDGET (ud->builder, "PictureTopCrop");
4072         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
4073         widget = GHB_WIDGET (ud->builder, "PictureBottomCrop");
4074         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
4075         bound = tinfo->width / 2 - 2;
4076         widget = GHB_WIDGET (ud->builder, "PictureLeftCrop");
4077         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
4078         widget = GHB_WIDGET (ud->builder, "PictureRightCrop");
4079         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
4080         if (ghb_settings_get_boolean(ud->settings, "PictureAutoCrop"))
4081         {
4082                 ghb_ui_update(ud, "PictureTopCrop", ghb_int64_value(tinfo->crop[0]));
4083                 ghb_ui_update(ud, "PictureBottomCrop", ghb_int64_value(tinfo->crop[1]));
4084                 ghb_ui_update(ud, "PictureLeftCrop", ghb_int64_value(tinfo->crop[2]));
4085                 ghb_ui_update(ud, "PictureRightCrop", ghb_int64_value(tinfo->crop[3]));
4086         }
4087 }
4088
4089 void
4090 ghb_refresh_preset(signal_user_data_t *ud)
4091 {
4092         ghb_title_info_t tinfo;
4093         GValue *preset;
4094         gint *indices, len;
4095
4096         g_debug("ghb_refresh_preset ()");
4097         preset = ghb_settings_get_value(ud->settings, "preset_selection");
4098         indices = ghb_preset_indices_from_path(presetsPlist, preset, &len);
4099         if (indices)
4100         {
4101                 gboolean folder;
4102
4103                 folder = ghb_presets_get_folder(presetsPlist, indices, len);
4104                 if (!folder)
4105                 {
4106                         ud->dont_clear_presets = TRUE;
4107                         // Temporarily set the video_quality range to (0,100)
4108                         // This is needed so the video_quality value does not get
4109                         // truncated when set.  The range will be readjusted below
4110                         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
4111                         gtk_range_set_range (GTK_RANGE(qp), 0, 100);
4112                         gtk_scale_set_digits(GTK_SCALE(qp), 3);
4113                         // Clear the audio list prior to changing the preset.  Existing 
4114                         // audio can cause the container extension to be automatically 
4115                         // changed when it shouldn't be
4116                         ghb_clear_audio_list(ud);
4117                         ghb_set_preset_from_indices(ud, indices, len);
4118                         gint titleindex;
4119                         titleindex = ghb_settings_combo_int(ud->settings, "title");
4120                         ghb_set_pref_audio(titleindex, ud);
4121                         ghb_set_pref_subtitle(titleindex, ud);
4122                         ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
4123                         if (ghb_get_title_info (&tinfo, titleindex))
4124                         {
4125                                 preset_update_title_deps(ud, &tinfo);
4126                         }
4127                         ghb_set_scale (ud, GHB_PIC_KEEP_PAR);
4128                         ud->dont_clear_presets = FALSE;
4129
4130                         gdouble vqmin, vqmax, step, page;
4131                         gint digits;
4132                         gboolean inverted;
4133
4134                         ghb_vquality_range(ud, &vqmin, &vqmax, &step, 
4135                                                                 &page, &digits, &inverted);
4136                         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
4137                         gtk_range_set_increments (GTK_RANGE(qp), step, page);
4138                         gtk_scale_set_digits(GTK_SCALE(qp), digits);
4139                         gtk_range_set_inverted (GTK_RANGE(qp), inverted);
4140
4141                         gchar *text;
4142                         gint crop[4];
4143                         GtkWidget *crop_widget;
4144                         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
4145                         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
4146                         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
4147                         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
4148                         crop_widget = GHB_WIDGET (ud->builder, "crop_values");
4149                         text = g_strdup_printf("%d:%d:%d:%d", 
4150                                                                         crop[0], crop[1], crop[2], crop[3]);
4151                         gtk_label_set_text (GTK_LABEL(crop_widget), text);
4152                         g_free(text);
4153                 }
4154         }
4155 }
4156
4157 G_MODULE_EXPORT void
4158 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
4159 {
4160         GtkTreeModel *store;
4161         GtkTreeIter iter;
4162         ghb_title_info_t tinfo;
4163         GtkWidget *widget;
4164         
4165         g_debug("presets_list_selection_changed_cb ()");
4166         widget = GHB_WIDGET (ud->builder, "presets_remove");
4167         if (gtk_tree_selection_get_selected(selection, &store, &iter))
4168         {
4169                 GtkTreePath *treepath;
4170                 gint *indices, len;
4171                 GValue *path;
4172                 gboolean folder;
4173
4174                 treepath = gtk_tree_model_get_path(store, &iter);
4175                 indices = gtk_tree_path_get_indices(treepath);
4176                 len = gtk_tree_path_get_depth(treepath);
4177
4178                 path = preset_path_from_indices(presetsPlist, indices, len);
4179                 ghb_settings_take_value(ud->settings, "preset_selection", path);
4180
4181                 folder = ghb_presets_get_folder(presetsPlist, indices, len);
4182                 if (!folder)
4183                 {
4184                         ud->dont_clear_presets = TRUE;
4185                         // Temporarily set the video_quality range to (0,100)
4186                         // This is needed so the video_quality value does not get
4187                         // truncated when set.  The range will be readjusted below
4188                         GtkWidget *qp = GHB_WIDGET(ud->builder, "VideoQualitySlider");
4189                         gtk_range_set_range (GTK_RANGE(qp), 0, 100);
4190                         gtk_scale_set_digits(GTK_SCALE(qp), 3);
4191                         // Clear the audio list prior to changing the preset.  Existing 
4192                         // audio can cause the container extension to be automatically 
4193                         // changed when it shouldn't be
4194                         ghb_clear_audio_list(ud);
4195                         ghb_set_preset_from_indices(ud, indices, len);
4196                         gint titleindex;
4197                         titleindex = ghb_settings_combo_int(ud->settings, "title");
4198                         ghb_set_pref_audio(titleindex, ud);
4199                         ghb_set_pref_subtitle(titleindex, ud);
4200                         ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
4201                         if (ghb_get_title_info (&tinfo, titleindex))
4202                         {
4203                                 preset_update_title_deps(ud, &tinfo);
4204                         }
4205                         ghb_set_scale (ud, GHB_PIC_KEEP_PAR);
4206                         ud->dont_clear_presets = FALSE;
4207
4208                         gdouble vqmin, vqmax, step, page;
4209                         gint digits;
4210                         gboolean inverted;
4211
4212                         ghb_vquality_range(ud, &vqmin, &vqmax, &step, 
4213                                                                 &page, &digits, &inverted);
4214                         gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
4215                         gtk_range_set_increments (GTK_RANGE(qp), step, page);
4216                         gtk_scale_set_digits(GTK_SCALE(qp), digits);
4217                         gtk_range_set_inverted (GTK_RANGE(qp), inverted);
4218
4219                         gchar *text;
4220                         gint crop[4];
4221                         GtkWidget *crop_widget;
4222                         crop[0] = ghb_settings_get_int(ud->settings, "PictureTopCrop");
4223                         crop[1] = ghb_settings_get_int(ud->settings, "PictureBottomCrop");
4224                         crop[2] = ghb_settings_get_int(ud->settings, "PictureLeftCrop");
4225                         crop[3] = ghb_settings_get_int(ud->settings, "PictureRightCrop");
4226                         crop_widget = GHB_WIDGET (ud->builder, "crop_values");
4227                         text = g_strdup_printf("%d:%d:%d:%d", 
4228                                                                         crop[0], crop[1], crop[2], crop[3]);
4229                         gtk_label_set_text (GTK_LABEL(crop_widget), text);
4230                         g_free(text);
4231                 }
4232                 gtk_tree_path_free(treepath);
4233                 gtk_widget_set_sensitive(widget, TRUE);
4234         }
4235         else
4236         {
4237                 g_debug("No selection???  Perhaps unselected.");
4238                 gtk_widget_set_sensitive(widget, FALSE);
4239         }
4240         if (ghb_settings_combo_int(ud->settings, "PtoPType") == 0)
4241         {
4242                 gint start, end;
4243                 start = ghb_settings_get_int(ud->settings, "start_point");
4244                 end = ghb_settings_get_int(ud->settings, "end_point");
4245                 widget = GHB_WIDGET (ud->builder, "ChapterMarkers");
4246                 gtk_widget_set_sensitive(widget, TRUE);
4247                 if (start == end)
4248                 {
4249                         ud->dont_clear_presets = TRUE;
4250                         ghb_ui_update(ud, "ChapterMarkers", ghb_boolean_value(FALSE));
4251                         ud->dont_clear_presets = FALSE;
4252                         gtk_widget_set_sensitive(widget, FALSE);
4253                 }
4254         }
4255 }
4256
4257 void
4258 ghb_clear_presets_selection(signal_user_data_t *ud)
4259 {
4260         GtkTreeView *treeview;
4261         GtkTreeSelection *selection;
4262         
4263         if (ud->dont_clear_presets) return;
4264         g_debug("ghb_clear_presets_selection()");
4265         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
4266         selection = gtk_tree_view_get_selection (treeview);
4267         gtk_tree_selection_unselect_all (selection);
4268         ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
4269 }
4270
4271 G_MODULE_EXPORT void
4272 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
4273 {
4274         GtkTreeView *treeview;
4275         GtkTreeSelection *selection;
4276         GtkTreeModel *store;
4277         GtkTreeIter iter;
4278         
4279         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
4280         selection = gtk_tree_view_get_selection(treeview);
4281         if (gtk_tree_selection_get_selected(selection, &store, &iter))
4282         {
4283                 GtkTreePath *path;
4284                 path = gtk_tree_model_get_path (store, &iter);
4285                 // Make the parent visible in scroll window if it is not.
4286                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
4287                 gtk_tree_path_free(path);
4288         }
4289 }
4290
4291 G_MODULE_EXPORT void
4292 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
4293 {
4294         GValue *preset;
4295         gint *indices, len;
4296
4297         g_debug("presets_default_clicked_cb ()");
4298         preset = ghb_settings_get_value(ud->settings, "preset_selection");
4299         indices = ghb_preset_indices_from_path(presetsPlist, preset, &len);
4300         if (indices)
4301         {
4302                 if (!ghb_presets_get_folder(presetsPlist, indices, len))
4303                 {
4304                         ghb_presets_list_clear_default(ud);
4305                         presets_set_default(indices, len);
4306                         ghb_presets_list_default(ud);
4307                 }
4308                 g_free(indices);
4309         }
4310 }
4311
4312 G_MODULE_EXPORT void
4313 preset_edited_cb(
4314         GtkCellRendererText *cell, 
4315         gchar *path, 
4316         gchar *text, 
4317         signal_user_data_t *ud)
4318 {
4319         GtkTreePath *treepath;
4320         GtkTreeStore *store;
4321         GtkTreeView *treeview;
4322         GtkTreeIter iter;
4323         gint *indices, len, count;
4324         GValue *dict;
4325         GValue *preset, *dest;
4326         
4327         g_debug("preset_edited_cb ()");
4328         g_debug("path (%s)", path);
4329         g_debug("text (%s)", text);
4330
4331         preset = ghb_settings_get_value (ud->settings, "preset_selection");
4332         dest = ghb_array_value_new(MAX_NESTED_PRESET);
4333         count = ghb_array_len(preset);
4334         ghb_array_copy(dest, preset, count-1);
4335         ghb_array_append(dest, ghb_string_value_new(text));
4336         indices = ghb_preset_indices_from_path(presetsPlist, dest, &len);
4337         ghb_value_free(dest);
4338         if (indices != NULL)
4339         {
4340                 // Already exists
4341                 g_free(indices);
4342                 return;
4343         }
4344
4345         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
4346         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
4347         treepath = gtk_tree_path_new_from_string (path);
4348         indices = gtk_tree_path_get_indices(treepath);
4349         len = gtk_tree_path_get_depth(treepath);
4350         gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath);
4351         gtk_tree_store_set(store, &iter, 0, text, -1);
4352
4353         dict = presets_get_dict(presetsPlist, indices, len);
4354         ghb_dict_insert(dict, g_strdup("PresetName"), ghb_string_value_new(text));
4355         store_presets();
4356         gtk_tree_path_free (treepath);
4357 }
4358