OSDN Git Service

LinGui: refactoring that will make nested presets easier to implement.
[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 <glib.h>
15 #include <glib-object.h>
16 #include <glib/gstdio.h>
17 #include <string.h>
18 #include <gtk/gtk.h>
19 #include "settings.h"
20 #include "audiohandler.h"
21 #include "hb-backend.h"
22 #include "plist.h"
23 #include "resources.h"
24 #include "presets.h"
25 #include "values.h"
26
27 static GValue *presetsPlist = NULL;
28 static GValue *internalPlist = NULL;
29 static GValue *prefsPlist = NULL;
30
31 static const GValue* preset_dict_get_value(GValue *dict, const gchar *key);
32
33 static GValue*
34 plist_get_dict(GValue *presets, const gchar *name)
35 {
36         if (presets == NULL || name == NULL) return NULL;
37         return ghb_dict_lookup(presets, name);
38 }
39
40 static const gchar*
41 preset_get_name(GValue *dict)
42 {
43         return g_value_get_string(ghb_dict_lookup(dict, "preset_name"));
44 }
45
46 static GValue*
47 presets_get_first_dict(GValue *presets)
48 {
49         GValue *dict;
50         gint count, ii, ptype;
51         
52         if (presets == NULL) return NULL;
53         count = ghb_array_len(presets);
54         for (ii = 0; ii < count; ii++)
55         {
56                 dict = ghb_array_get_nth(presets, ii);
57                 ptype = ghb_value_int(preset_dict_get_value(dict, "preset_type"));
58                 if (ptype != 2)
59                         return dict;
60         }
61         return NULL;
62 }
63
64 static GValue*
65 presets_get_dict(GValue *presets, const gchar *name)
66 {
67         GValue *dict;
68         gint count, ii;
69         
70         if (presets == NULL || name == NULL) return NULL;
71         count = ghb_array_len(presets);
72         for (ii = 0; ii < count; ii++)
73         {
74                 const gchar *str;
75                 dict = ghb_array_get_nth(presets, ii);
76                 str = preset_get_name(dict);
77                 if (strcmp(str, name) == 0)
78                         return dict;
79         }
80         return NULL;
81 }
82
83 static gint
84 presets_remove(GValue *presets, const gchar *name)
85 {
86         GValue *dict;
87         gint count, ii;
88         
89         if (presets == NULL || name == NULL) return -1;
90         count = ghb_array_len(presets);
91         for (ii = 0; ii < count; ii++)
92         {
93                 const gchar *str;
94                 dict = ghb_array_get_nth(presets, ii);
95                 str = preset_get_name(dict);
96                 if (strcmp(str, name) == 0)
97                 {
98                         ghb_array_remove(presets, ii);
99                         return ii;
100                 }
101         }
102         return -1;
103 }
104
105 static gint
106 presets_find_pos(GValue *presets, const gchar *name, gint type)
107 {
108         GValue *dict;
109         gint count, ii, ptype, last;
110         
111         if (presets == NULL || name == NULL) return -1;
112         last = count = ghb_array_len(presets);
113         for (ii = 0; ii < count; ii++)
114         {
115                 const gchar *str;
116                 dict = ghb_array_get_nth(presets, ii);
117                 str = preset_get_name(dict);
118                 ptype = ghb_value_int(preset_dict_get_value(dict, "preset_type"));
119                 if (strcasecmp(name, str) < 0 && ptype == type)
120                 {
121                         return ii;
122                 }
123                 if (ptype == type)
124                         last = ii+1;
125         }
126         return last;
127 }
128
129 void
130 ghb_set_preset_default(GValue *settings)
131 {
132         gchar *preset;
133         
134         preset = ghb_settings_get_string (settings, "preset");
135         ghb_settings_set_string(settings, "default_preset", preset);
136         ghb_prefs_save(settings);
137         g_free(preset);
138 }
139
140 // Used for sorting dictionaries.
141 gint
142 key_cmp(gconstpointer a, gconstpointer b)
143 {
144         gchar *stra = (gchar*)a;
145         gchar *strb = (gchar*)b;
146
147         return strcmp(stra, strb);
148 }
149
150 const gchar*
151 ghb_presets_get_description(GValue *pdict)
152 {
153         if (pdict == NULL) return g_strdup("");
154         return g_value_get_string(ghb_dict_lookup(pdict, "preset_description"));
155 }
156
157 static const GValue*
158 preset_dict_get_value(GValue *dict, const gchar *key)
159 {
160         const GValue *gval = NULL;
161
162         if (dict)
163         {
164                 gval = ghb_dict_lookup(dict, key);
165         }
166         if (internalPlist == NULL) return NULL;
167         if (gval == NULL)
168         {
169                 dict = plist_get_dict(internalPlist, "Presets");
170                 if (dict == NULL) return NULL;
171                 gval = ghb_dict_lookup(dict, key);
172         }
173         return gval;
174 }
175
176 static const GValue*
177 preset_get_value(const gchar *name, const gchar *key)
178 {
179         GValue *dict;
180
181         dict = presets_get_dict(presetsPlist, name);
182         return preset_dict_get_value(dict, key);
183 }
184
185 gint
186 ghb_preset_flags(GValue *dict)
187 {
188         const GValue *gval;
189         gint ptype;
190         gint ret = 0;
191
192         gval = preset_dict_get_value(dict, "preset_type");
193         if (gval)
194         {
195                 ptype = ghb_value_int(gval);
196                 ret = (ptype != 0 ? PRESET_CUSTOM : 0);
197         }
198         return ret;
199 }
200
201 static void init_settings_from_dict(
202         GValue *dest, GValue *internal, GValue *dict);
203
204 static void
205 init_settings_from_array(
206         GValue *dest, 
207         GValue *internal,
208         GValue *array)
209 {
210         GValue *gval, *val;
211         gint count, ii;
212         
213         count = ghb_array_len(array);
214         // The first element of the internal version is always the 
215         // template for the allowed values
216         gval = ghb_array_get_nth(internal, 0);
217         for (ii = 0; ii < count; ii++)
218         {
219                 val = NULL;
220                 val = ghb_array_get_nth(array, ii);
221                 if (val == NULL)
222                         val = gval;
223                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
224                 {
225                         GValue *new_dict;
226                         new_dict = ghb_dict_value_new();
227                         ghb_array_append(dest, new_dict);
228                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
229                                 init_settings_from_dict(new_dict, gval, val);
230                         else
231                                 init_settings_from_dict(new_dict, gval, gval);
232                 }
233                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
234                 {
235                         GValue *new_array;
236                         new_array = ghb_array_value_new(8);
237                         ghb_array_append(dest, new_array);
238                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
239                                 init_settings_from_array(new_array, gval, val);
240                         else
241                                 init_settings_from_array(new_array, gval, gval);
242                 }
243                 else
244                 {
245                         ghb_array_append(dest, val);
246                 }
247         }
248 }
249
250 static void
251 init_settings_from_dict(
252         GValue *dest, 
253         GValue *internal,
254         GValue *dict)
255 {
256         GHashTableIter iter;
257         gchar *key;
258         GValue *gval, *val;
259         
260         ghb_dict_iter_init(&iter, internal);
261         // middle (void*) cast prevents gcc warning "defreferencing type-punned
262         // pointer will break strict-aliasing rules"
263         while (g_hash_table_iter_next(
264                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
265         {
266                 val = NULL;
267                 if (dict)
268                         val = ghb_dict_lookup(dict, key);
269                 if (val == NULL)
270                         val = gval;
271                 if (G_VALUE_TYPE(gval) == ghb_dict_get_type())
272                 {
273                         GValue *new_dict;
274                         new_dict = ghb_dict_value_new();
275                         ghb_settings_take_value(dest, key, new_dict);
276                         if (G_VALUE_TYPE(val) == ghb_dict_get_type())
277                                 init_settings_from_dict(new_dict, gval, val);
278                         else
279                                 init_settings_from_dict(new_dict, gval, gval);
280                 }
281                 else if (G_VALUE_TYPE(gval) == ghb_array_get_type())
282                 {
283                         GValue *new_array;
284                         new_array = ghb_array_value_new(8);
285                         ghb_settings_take_value(dest, key, new_array);
286                         if (G_VALUE_TYPE(val) == ghb_array_get_type())
287                                 init_settings_from_array(new_array, gval, val);
288                         else
289                                 init_settings_from_array(new_array, gval, gval);
290         
291                 }
292                 else
293                 {
294                         ghb_settings_set_value(dest, key, val);
295                 }
296         }
297 }
298
299 void
300 init_ui_from_dict(
301         signal_user_data_t *ud, 
302         GValue *internal,
303         GValue *dict)
304 {
305         GHashTableIter iter;
306         gchar *key;
307         GValue *gval, *val;
308         
309         ghb_dict_iter_init(&iter, internal);
310         // middle (void*) cast prevents gcc warning "defreferencing type-punned
311         // pointer will break strict-aliasing rules"
312         while (g_hash_table_iter_next(
313                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
314         {
315                 val = NULL;
316                 if (dict)
317                         val = ghb_dict_lookup(dict, key);
318                 if (val == NULL)
319                         val = gval;
320                 ghb_ui_update(ud, key, val);
321         }
322 }
323
324 static void
325 preset_to_ui(signal_user_data_t *ud, GValue *dict)
326 {
327         g_debug("preset_to_ui()\n");
328         // Initialize the ui from presets file.
329         GValue *internal;
330
331         // Get key list from internal default presets.  This way we do not
332         // load any unknown keys.
333         if (internalPlist == NULL) return;
334         internal = plist_get_dict(internalPlist, "Presets");
335         // Setting a ui widget will cause the corresponding setting
336         // to be set, but it also triggers a callback that can 
337         // have the side effect of using other settings values
338         // that have not yet been set.  So set *all* settings first
339         // then update the ui.
340         init_settings_from_dict(ud->settings, internal, dict);
341         init_ui_from_dict(ud, internal, dict);
342
343         if (ghb_settings_get_boolean(ud->settings, "allow_tweaks"))
344         {
345                 const GValue *gval;
346                 gval = preset_dict_get_value(dict, "deinterlace");
347                 if (gval)
348                 {
349                         ghb_ui_update(ud, "tweak_deinterlace", gval);
350                 }
351                 gval = preset_dict_get_value(dict, "denoise");
352                 if (gval)
353                 {
354                         ghb_ui_update(ud, "tweak_denoise", gval);
355                 }
356         }
357 }
358
359 void
360 ghb_set_preset(signal_user_data_t *ud, const gchar *name)
361 {
362         GValue *dict;
363         
364         g_debug("ghb_set_preset() %s\n", name);
365         if (name == NULL)
366         {
367                 dict = presets_get_first_dict(presetsPlist);
368                 name = preset_get_name(dict);
369         }
370         else
371         {
372                 dict = presets_get_dict(presetsPlist, name);
373         }
374         if (dict == NULL || name == NULL)
375         {
376                 preset_to_ui(ud, NULL);
377         }
378         else
379         {
380                 preset_to_ui(ud, dict);
381                 ghb_settings_set_string(ud->settings, "preset", name);
382         }
383 }
384
385 void
386 ghb_update_from_preset(
387         signal_user_data_t *ud, 
388         const gchar *name, 
389         const gchar *key)
390 {
391         const GValue *gval;
392         
393         g_debug("ghb_update_from_preset() %s %s", name, key);
394         if (name == NULL) return;
395         gval = preset_get_value(name, key);
396         if (gval != NULL)
397         {
398                 ghb_ui_update(ud, key, gval);
399         }
400 }
401
402 gchar*
403 ghb_get_user_config_dir()
404 {
405         const gchar *dir;
406         gchar *config;
407
408         dir = g_get_user_config_dir();
409         if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
410         {
411                 dir = g_get_home_dir();
412                 config = g_strdup_printf ("%s/.ghb", dir);
413                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
414                         g_mkdir (config, 0755);
415         }
416         else
417         {
418                 config = g_strdup_printf ("%s/ghb", dir);
419                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
420                         g_mkdir (config, 0755);
421         }
422         return config;
423 }
424
425 static void
426 store_plist(GValue *plist, const gchar *name)
427 {
428         gchar *config, *path;
429         FILE *file;
430
431         config = ghb_get_user_config_dir();
432         path = g_strdup_printf ("%s/%s", config, name);
433         file = g_fopen(path, "w");
434         g_free(config);
435         g_free(path);
436         ghb_plist_write(file, plist);
437         fclose(file);
438 }
439
440 static GValue*
441 load_plist(const gchar *name)
442 {
443         gchar *config, *path;
444         GValue *plist = NULL;
445
446         config = ghb_get_user_config_dir();
447         path = g_strdup_printf ("%s/%s", config, name);
448         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
449         {
450                 plist = ghb_plist_parse_file(path);
451         }
452         g_free(config);
453         g_free(path);
454         return plist;
455 }
456
457 static void
458 remove_plist(const gchar *name)
459 {
460         gchar *config, *path;
461
462         config = ghb_get_user_config_dir();
463         path = g_strdup_printf ("%s/%s", config, name);
464         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
465         {
466                 g_unlink(path);
467         }
468         g_free(path);
469         g_free(config);
470 }
471
472 static gboolean prefs_initializing = FALSE;
473
474 void
475 ghb_prefs_to_ui(signal_user_data_t *ud)
476 {
477         const GValue *gval;
478         gchar *key;
479         gchar *str;
480         GValue *internal, *dict;
481         GHashTableIter iter;
482         
483
484         prefs_initializing = TRUE;
485
486         // Setting a ui widget will cause the corresponding setting
487         // to be set, but it also triggers a callback that can 
488         // have the side effect of using other settings values
489         // that have not yet been set.  So set *all* settings first
490         // then update the ui.
491         internal = plist_get_dict(internalPlist, "Initialization");
492         ghb_dict_iter_init(&iter, internal);
493         // middle (void*) cast prevents gcc warning "defreferencing type-punned
494         // pointer will break strict-aliasing rules"
495         while (g_hash_table_iter_next(
496                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
497         {
498                 ghb_ui_update(ud, key, gval);
499         }
500
501         dict = plist_get_dict(prefsPlist, "Preferences");
502         internal = plist_get_dict(internalPlist, "Preferences");
503         ghb_dict_iter_init(&iter, internal);
504         // middle (void*) cast prevents gcc warning "defreferencing type-punned
505         // pointer will break strict-aliasing rules"
506         while (g_hash_table_iter_next(
507                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
508     {
509                 const GValue *value = NULL;
510                 if (dict)
511                         value = ghb_dict_lookup(dict, key);
512                 if (value == NULL)
513                         value = gval;
514                 ghb_settings_set_value(ud->settings, key, value);
515     }
516         internal = plist_get_dict(internalPlist, "Preferences");
517         ghb_dict_iter_init(&iter, internal);
518         // middle (void*) cast prevents gcc warning "defreferencing type-punned
519         // pointer will break strict-aliasing rules"
520         while (g_hash_table_iter_next(
521                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
522         {
523                 const GValue *value = NULL;
524                 if (dict)
525                         value = ghb_dict_lookup(dict, key);
526                 if (value == NULL)
527                         value = gval;
528                 ghb_ui_update(ud, key, value);
529         }
530         const GValue *val;
531         val = ghb_settings_get_value(ud->settings, "show_presets");
532         ghb_ui_update(ud, "show_presets", val);
533         if (ghb_settings_get_boolean(ud->settings, "hbfd_feature"))
534         {
535                 GtkAction *action;
536                 val = ghb_settings_get_value(ud->settings, "hbfd");
537                 ghb_ui_update(ud, "hbfd", val);
538                 action = GHB_ACTION (ud->builder, "hbfd");
539                 gtk_action_set_visible(action, TRUE);
540         }
541         else
542         {
543                 ghb_ui_update(ud, "hbfd", ghb_int64_value(0));
544         }
545         gval = ghb_settings_get_value(ud->settings, "default_source");
546         ghb_settings_set_value (ud->settings, "source", gval);
547         str = ghb_settings_get_string(ud->settings, "destination_dir");
548
549         gchar *path = g_strdup_printf ("%s/new_video.mp4", str);
550         ghb_ui_update(ud, "destination", ghb_string_value(path));
551         g_free(str);
552         g_free(path);
553
554         prefs_initializing = FALSE;
555 }
556
557 void
558 ghb_prefs_save(GValue *settings)
559 {
560         GValue *dict;
561         GValue *pref_dict;
562         GHashTableIter iter;
563         gchar *key;
564         const GValue *value;
565         
566         if (prefs_initializing) return;
567         dict = plist_get_dict(internalPlist, "Preferences");
568         if (dict == NULL) return;
569         pref_dict = plist_get_dict(prefsPlist, "Preferences");
570         if (pref_dict == NULL) return;
571         ghb_dict_iter_init(&iter, dict);
572         // middle (void*) cast prevents gcc warning "defreferencing type-punned
573         // pointer will break strict-aliasing rules"
574         while (g_hash_table_iter_next(
575                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
576     {
577             value = ghb_settings_get_value(settings, key);
578             if (value != NULL)
579             {
580                         ghb_dict_insert(pref_dict, g_strdup(key), ghb_value_dup(value));
581             }
582         }
583     store_plist(prefsPlist, "preferences");
584 }
585
586 void
587 ghb_pref_save(GValue *settings, const gchar *key)
588 {
589         const GValue *value;
590         
591         if (prefs_initializing) return;
592         value = ghb_settings_get_value(settings, key);
593         if (value != NULL)
594         {
595                 GValue *dict;
596                 dict = plist_get_dict(prefsPlist, "Preferences");
597                 if (dict == NULL) return;
598                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
599                 store_plist(prefsPlist, "preferences");
600         }
601 }
602
603 void
604 ghb_settings_init(signal_user_data_t *ud)
605 {
606         GValue *internal;
607         GHashTableIter iter;
608         gchar *key;
609         GValue *gval;
610
611
612         g_debug("ghb_settings_init");
613         prefs_initializing = TRUE;
614
615         internalPlist = ghb_resource_get("internal-defaults");
616         // Setting a ui widget will cause the corresponding setting
617         // to be set, but it also triggers a callback that can 
618         // have the side effect of using other settings values
619         // that have not yet been set.  So set *all* settings first
620         // then update the ui.
621         internal = plist_get_dict(internalPlist, "Initialization");
622         ghb_dict_iter_init(&iter, internal);
623         // middle (void*) cast prevents gcc warning "defreferencing type-punned
624         // pointer will break strict-aliasing rules"
625         while (g_hash_table_iter_next(
626                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
627         {
628                 ghb_settings_set_value(ud->settings, key, gval);
629         }
630
631         internal = plist_get_dict(internalPlist, "Presets");
632         ghb_dict_iter_init(&iter, internal);
633         // middle (void*) cast prevents gcc warning "defreferencing type-punned
634         // pointer will break strict-aliasing rules"
635         while (g_hash_table_iter_next(
636                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
637         {
638                 ghb_settings_set_value(ud->settings, key, gval);
639         }
640
641         internal = plist_get_dict(internalPlist, "Preferences");
642         ghb_dict_iter_init(&iter, internal);
643         // middle (void*) cast prevents gcc warning "defreferencing type-punned
644         // pointer will break strict-aliasing rules"
645         while (g_hash_table_iter_next(
646                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
647         {
648                 ghb_settings_set_value(ud->settings, key, gval);
649         }
650         prefs_initializing = FALSE;
651 }
652
653 void
654 ghb_settings_close()
655 {
656         if (internalPlist)
657                 ghb_value_free(internalPlist);
658         if (presetsPlist)
659                 ghb_value_free(presetsPlist);
660         if (prefsPlist)
661                 ghb_value_free(prefsPlist);
662 }
663
664 void
665 ghb_prefs_load(signal_user_data_t *ud)
666 {
667         GValue *dict, *internal;
668         GHashTableIter iter;
669         gchar *key;
670         GValue *gval;
671         
672         g_debug("ghb_prefs_load");
673         prefsPlist = load_plist("preferences");
674         if (prefsPlist == NULL)
675                 prefsPlist = ghb_dict_value_new();
676         dict = plist_get_dict(prefsPlist, "Preferences");
677         internal = plist_get_dict(internalPlist, "Preferences");
678     if (dict == NULL && internal)
679     {
680                 dict = ghb_dict_value_new();
681                 ghb_dict_insert(prefsPlist, g_strdup("Preferences"), dict);
682
683         // Get defaults from internal defaults 
684                 ghb_dict_iter_init(&iter, internal);
685                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
686                 // pointer will break strict-aliasing rules"
687                 while (g_hash_table_iter_next(
688                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
689         {
690                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
691         }
692                 const gchar *dir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
693                 if (dir == NULL)
694                 {
695                         dir = ".";
696                 }
697                 ghb_dict_insert(dict, 
698                         g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
699                 store_plist(prefsPlist, "preferences");
700     }
701 }
702
703 void
704 ghb_presets_reload(signal_user_data_t *ud)
705 {
706         GValue *std_presets;
707         gint count, ii;
708
709         g_debug("ghb_presets_reload()\n");
710         std_presets = ghb_resource_get("standard-presets");
711         if (std_presets == NULL) return;
712
713         // Merge the keyfile contents into our presets
714         count = ghb_array_len(std_presets);
715         for (ii = 0; ii < count; ii++)
716         {
717                 const gchar *name;
718                 GValue *std_dict;
719                 GValue *copy_dict;
720                 GHashTableIter iter;
721                 gchar *key;
722                 GValue *value;
723                 gint pos;
724
725                 std_dict = ghb_array_get_nth(std_presets, ii);
726                 name = preset_get_name(std_dict);
727                 presets_remove(presetsPlist, name);
728
729                 copy_dict = ghb_dict_value_new();
730                 pos = presets_find_pos(presetsPlist, name, 0);
731                 ghb_array_insert(presetsPlist, pos, copy_dict);
732                 ghb_dict_iter_init(&iter, std_dict);
733                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
734                 // pointer will break strict-aliasing rules"
735                 while (g_hash_table_iter_next(
736                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
737                 {
738                         ghb_dict_insert(copy_dict, g_strdup(key), ghb_value_dup(value));
739                 }
740         }
741         store_plist(presetsPlist, "presets");
742 }
743
744 static void
745 presets_store()
746 {
747         g_debug("presets_store ()\n");
748         store_plist(presetsPlist, "presets");
749 }
750
751 void
752 ghb_save_queue(GValue *queue)
753 {
754         store_plist(queue, "queue");
755 }
756
757 GValue*
758 ghb_load_queue()
759 {
760         return load_plist("queue");
761 }
762
763 void
764 ghb_remove_queue_file()
765 {
766         remove_plist("queue");
767 }
768
769 void
770 ghb_presets_load()
771 {
772         presetsPlist = load_plist("presets");
773         if (presetsPlist == NULL)
774         {
775                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
776                 presets_store();
777         }
778         if (G_VALUE_TYPE(presetsPlist) == ghb_dict_get_type())
779         { // Presets is older dictionary format. Convert to array
780                 GHashTableIter old_iter;
781                 GValue *presets;
782                 gchar *name;
783                 GValue *orig_dict;
784
785                 presets = ghb_array_value_new(32);
786                 ghb_dict_iter_init(&old_iter, presetsPlist);
787                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
788                 // pointer will break strict-aliasing rules"
789                 while (g_hash_table_iter_next(
790                         &old_iter, (gpointer*)(void*)&name, (gpointer*)(void*)&orig_dict))
791                 {
792                         GHashTableIter iter;
793                         gchar *key;
794                         GValue *value, *dict;
795
796                         dict = ghb_dict_value_new();
797                         ghb_dict_insert(dict, g_strdup("preset_name"), 
798                                 ghb_string_value_new(name));
799                         ghb_array_append(presets, dict);
800                         ghb_dict_iter_init(&iter, orig_dict);
801                         // middle (void*) cast prevents gcc warning "defreferencing 
802                         // type-punned pointer will break strict-aliasing rules"
803                         while (g_hash_table_iter_next(
804                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
805                         {
806                                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
807                         }
808                 }
809                 ghb_value_free(presetsPlist);
810                 presetsPlist = presets;
811                 presets_store();
812         }
813 }
814
815 void
816 ghb_settings_save(signal_user_data_t *ud, const gchar *name)
817 {
818         GValue *dict, *internal;
819         GHashTableIter iter;
820         gchar *key;
821         GValue *value;
822         gboolean autoscale;
823
824         if (internalPlist == NULL) return;
825         if (ghb_settings_get_boolean(ud->settings, "allow_tweaks"))
826         {
827                 gchar *str;
828                 str = ghb_settings_get_string(ud->settings, "tweak_deinterlace");
829                 if (str)
830                 {
831                         ghb_settings_set_string(ud->settings, "deinterlace", str);
832                         g_free(str);
833                 }
834                 str = ghb_settings_get_string(ud->settings, "tweak_denoise");
835                 if (str)
836                 {
837                         ghb_settings_set_string(ud->settings, "denoise", str);
838                         g_free(str);
839                 }
840         }
841         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
842         ghb_settings_set_int64(ud->settings, "preset_type", 1);
843
844         dict = ghb_dict_value_new();
845         ghb_dict_insert(dict, g_strdup("preset_name"), ghb_string_value_new(name));
846         gint pos = presets_find_pos(presetsPlist, name, 1);
847         ghb_array_insert(presetsPlist, pos, dict);
848         internal = plist_get_dict(internalPlist, "Presets");
849
850         ghb_dict_iter_init(&iter, internal);
851         // middle (void*) cast prevents gcc warning "defreferencing type-punned
852         // pointer will break strict-aliasing rules"
853         while (g_hash_table_iter_next(
854                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
855         {
856                 const GValue *gval;
857                 gchar *key2;
858
859                 key2 = key;
860                 if (!autoscale)
861                 {
862                         if (strcmp(key, "max_width") == 0)
863                         {
864                                 key2 = "scale_width";
865                         }
866                         else if (strcmp(key, "max_height") == 0)
867                         {
868                                 key2 = "scale_height";
869                         }
870                 }
871                 gval = ghb_settings_get_value(ud->settings, key2);
872                 if (gval == NULL)
873                 {
874                         g_debug("Setting (%s) is not in defaults\n", (gchar*)key);
875                         continue;
876                 }
877                 if (ghb_value_cmp(gval, value) != 0)
878                 {
879                         // Differs from default value.  Store it.
880                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
881                 }
882         }
883         presets_store();
884         ud->dont_clear_presets = TRUE;
885         ghb_set_preset (ud, name);
886         ud->dont_clear_presets = FALSE;
887 }
888
889 void
890 ghb_presets_remove(const gchar *name)
891 {
892         if (presets_get_dict(presetsPlist, name))
893         {
894                 presets_remove(presetsPlist, name);
895                 presets_store();
896         }
897 }
898
899 void
900 ghb_presets_list_update(signal_user_data_t *ud)
901 {
902         GtkTreeView *treeview;
903         GtkTreeIter iter;
904         GtkTreeStore *store;
905         gboolean done;
906         const gchar *preset;
907         gchar *def_preset;
908         const gchar *description;
909         gint flags, custom, def;
910         gint count, ii;
911         GValue *dict;
912         
913         g_debug("ghb_presets_list_update ()");
914         def_preset = ghb_settings_get_string(ud->settings, "default_preset");
915         count = ghb_array_len(presetsPlist);
916         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
917         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
918         ii = 0;
919         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
920         {
921                 do
922                 {
923                         if (ii < count)
924                         {
925                                 // Update row with settings data
926                                 g_debug("Updating row");
927                                 dict = ghb_array_get_nth(presetsPlist, ii);
928                                 preset = preset_get_name(dict);
929                                 def = 0;
930                                 if (strcmp(preset, def_preset) == 0)
931                                         def = PRESET_DEFAULT;
932                                 
933                                 description = ghb_presets_get_description(dict);
934                                 flags = ghb_preset_flags(dict);
935                                 custom = flags & PRESET_CUSTOM;
936                                 gtk_tree_store_set(store, &iter, 
937                                                         0, preset, 
938                                                         1, def ? 800 : 400, 
939                                                         2, def ? 2 : 0,
940                                                         3, custom ? "black" : "blue", 
941                                                         4, description,
942                                                         -1);
943                                 ii++;
944                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
945                         }
946                         else
947                         {
948                                 // No more settings data, remove row
949                                 g_debug("Removing row");
950                                 done = !gtk_tree_store_remove(store, &iter);
951                         }
952                 } while (!done);
953         }
954         while (ii < count)
955         {
956                 // Additional settings, add row
957                 g_debug("Adding rows");
958                 dict = ghb_array_get_nth(presetsPlist, ii);
959                 preset = preset_get_name(dict);
960                 def = 0;
961                 if (strcmp(preset, def_preset) == 0)
962                         def = PRESET_DEFAULT;
963
964                 description = ghb_presets_get_description(dict);
965                 gtk_tree_store_append(store, &iter, NULL);
966                 flags = ghb_preset_flags(dict);
967                 custom = flags & PRESET_CUSTOM;
968                 gtk_tree_store_set(store, &iter, 0, preset, 
969                                                         1, def ? 800 : 400, 
970                                                         2, def ? 2 : 0,
971                                                         3, custom ? "black" : "blue", 
972                                                         4, description,
973                                                         -1);
974                 ii++;
975         }
976         g_free(def_preset);
977 }
978
979 void
980 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
981 {
982         GtkTreeView *treeview;
983         GtkTreeSelection *selection;
984         GtkTreeModel *store;
985         GtkTreeIter iter;
986         gchar *tpreset;
987         gboolean done;
988         gboolean foundit = FALSE;
989         
990         g_debug("select_preset()");
991         if (preset == NULL) return;
992         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
993         selection = gtk_tree_view_get_selection (treeview);
994         store = gtk_tree_view_get_model (treeview);
995         if (gtk_tree_model_get_iter_first(store, &iter))
996         {
997                 do
998                 {
999                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1000                         if (strcmp(preset, tpreset) == 0)
1001                         {
1002                                 gtk_tree_selection_select_iter (selection, &iter);
1003                                 foundit = TRUE;
1004                                 g_free(tpreset);
1005                                 break;
1006                         }
1007                         g_free(tpreset);
1008                         done = !gtk_tree_model_iter_next(store, &iter);
1009                 } while (!done);
1010         }
1011         if (!foundit)
1012         {
1013                 gtk_tree_model_get_iter_first(store, &iter);
1014                 gtk_tree_selection_select_iter (selection, &iter);
1015         }
1016 }
1017
1018 static void
1019 update_audio_presets(signal_user_data_t *ud)
1020 {
1021         g_debug("update_audio_presets");
1022         const GValue *audio_list;
1023
1024         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
1025         ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
1026 }
1027
1028 void
1029 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1030 {
1031         GtkWidget *dialog;
1032         GtkEntry *entry;
1033         GtkTextView *desc;
1034         GtkResponseType response;
1035         gchar *preset;
1036
1037         g_debug("presets_save_clicked_cb ()");
1038         preset = ghb_settings_get_string (ud->settings, "preset");
1039         // Clear the description
1040         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1041         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1042         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1043         gtk_entry_set_text(entry, preset);
1044         g_free(preset);
1045         response = gtk_dialog_run(GTK_DIALOG(dialog));
1046         gtk_widget_hide(dialog);
1047         if (response == GTK_RESPONSE_OK)
1048         {
1049                 // save the preset
1050                 const gchar *name = gtk_entry_get_text(entry);
1051                 g_debug("description to settings");
1052                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1053                 // Construct the audio settings presets from the current audio list
1054                 update_audio_presets(ud);
1055                 ghb_settings_save(ud, name);
1056                 ghb_presets_list_update(ud);
1057                 // Make the new preset the selected item
1058                 ghb_select_preset(ud->builder, name);
1059         }
1060 }
1061
1062 void
1063 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1064 {
1065         g_debug("presets_restore_clicked_cb ()");
1066         // Reload only the standard presets
1067         ghb_presets_reload(ud);
1068         ghb_presets_list_update(ud);
1069         // Updating the presets list shuffles things around
1070         // need to make sure the proper preset is selected
1071         gchar *preset = ghb_settings_get_string (ud->settings, "preset");
1072         ghb_select_preset(ud->builder, preset);
1073         g_free(preset);
1074 }
1075
1076 void
1077 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1078 {
1079         GtkTreeView *treeview;
1080         GtkTreeSelection *selection;
1081         GtkTreeModel *store;
1082         GtkTreeIter iter;
1083         gchar *preset;
1084         GtkResponseType response;
1085
1086         g_debug("presets_remove_clicked_cb ()");
1087         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1088         selection = gtk_tree_view_get_selection (treeview);
1089         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1090         {
1091                 GtkWidget *dialog;
1092
1093                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1094                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1095                                                                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1096                                                                 "Confirm deletion of preset %s.", preset);
1097                 response = gtk_dialog_run(GTK_DIALOG(dialog));
1098                 gtk_widget_destroy (dialog);
1099                 if (response == GTK_RESPONSE_YES)
1100                 {
1101                         GtkTreeIter nextIter = iter;
1102                         gchar *nextPreset = NULL;
1103                         if (!gtk_tree_model_iter_next(store, &nextIter))
1104                         {
1105                                 if (gtk_tree_model_get_iter_first(store, &nextIter))
1106                                 {
1107                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1108                                 }
1109                         }
1110                         else
1111                         {
1112                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1113                         }
1114                         // Remove the selected item
1115                         // First unselect it so that selecting the new item works properly
1116                         gtk_tree_selection_unselect_iter (selection, &iter);
1117                         ghb_presets_remove(preset);
1118                         ghb_presets_list_update(ud);
1119                         ghb_select_preset(ud->builder, nextPreset);
1120                 }
1121         }
1122 }
1123
1124 static void
1125 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1126 {
1127         GtkWidget *widget;
1128
1129         ghb_ui_update(ud, "scale_width", 
1130                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1131         // If anamorphic or keep_aspect, the hight will be automatically calculated
1132         gboolean keep_aspect, anamorphic;
1133         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
1134         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
1135         if (!(keep_aspect || anamorphic))
1136         {
1137                 ghb_ui_update(ud, "scale_height", 
1138                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1139         }
1140
1141         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1142         // you pass it a cropped width or height == 0.
1143         gint bound;
1144         bound = tinfo->height / 2 - 2;
1145         widget = GHB_WIDGET (ud->builder, "crop_top");
1146         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1147         widget = GHB_WIDGET (ud->builder, "crop_bottom");
1148         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1149         bound = tinfo->width / 2 - 2;
1150         widget = GHB_WIDGET (ud->builder, "crop_left");
1151         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1152         widget = GHB_WIDGET (ud->builder, "crop_right");
1153         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1154         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
1155         {
1156                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
1157                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
1158                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
1159                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
1160         }
1161 }
1162
1163 void
1164 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1165 {
1166         GtkTreeModel *store;
1167         GtkTreeIter iter;
1168         gchar *preset;
1169         ghb_title_info_t tinfo;
1170         GtkWidget *widget;
1171         
1172         g_debug("presets_list_selection_changed_cb ()");
1173         widget = GHB_WIDGET (ud->builder, "presets_remove");
1174         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1175         {
1176                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1177                 ud->dont_clear_presets = TRUE;
1178                 // Temporarily set the video_quality range to (0,100)
1179                 // This is needed so the video_quality value does not get
1180                 // truncated when set.  The range will be readjusted below
1181                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1182                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1183                 // Clear the audio list prior to changing the preset.  Existing audio
1184                 // can cause the container extension to be automatically changed when
1185                 // it shouldn't be
1186                 ghb_clear_audio_list(ud);
1187                 ghb_set_preset(ud, preset);
1188                 gint titleindex;
1189                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1190                 ghb_set_pref_audio(titleindex, ud);
1191                 ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
1192                 ud->dont_clear_presets = FALSE;
1193                 if (ghb_get_title_info (&tinfo, titleindex))
1194                 {
1195                         preset_update_title_deps(ud, &tinfo);
1196                 }
1197                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1198
1199                 gint vqmin, vqmax;
1200                 ghb_vquality_range(ud, &vqmin, &vqmax);
1201                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1202                 gtk_widget_set_sensitive(widget, TRUE);
1203         }
1204         else
1205         {
1206                 g_debug("No selection???  Perhaps unselected.");
1207                 gtk_widget_set_sensitive(widget, FALSE);
1208         }
1209 }
1210
1211 void
1212 ghb_clear_presets_selection(signal_user_data_t *ud)
1213 {
1214         GtkTreeView *treeview;
1215         GtkTreeSelection *selection;
1216         
1217         if (ud->dont_clear_presets) return;
1218         g_debug("ghb_clear_presets_selection()");
1219         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1220         selection = gtk_tree_view_get_selection (treeview);
1221         gtk_tree_selection_unselect_all (selection);
1222         ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
1223 }
1224
1225 void
1226 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
1227 {
1228         GtkTreeView *treeview;
1229         GtkTreeSelection *selection;
1230         GtkTreeModel *store;
1231         GtkTreeIter iter;
1232         
1233         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1234         selection = gtk_tree_view_get_selection(treeview);
1235         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1236         {
1237                 GtkTreePath *path;
1238                 path = gtk_tree_model_get_path (store, &iter);
1239                 // Make the parent visible in scroll window if it is not.
1240                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
1241                 gtk_tree_path_free(path);
1242         }
1243 }
1244
1245 void
1246 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1247 {
1248         ghb_set_preset_default(ud->settings);
1249         ghb_presets_list_update(ud);
1250 }
1251