OSDN Git Service

LinGui: queue item editing
[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_settings_to_ui(signal_user_data_t *ud, GValue *dict)
361 {
362         init_ui_from_dict(ud, dict, dict);
363 }
364
365 void
366 ghb_set_preset(signal_user_data_t *ud, const gchar *name)
367 {
368         GValue *dict;
369         
370         g_debug("ghb_set_preset() %s\n", name);
371         if (name == NULL)
372         {
373                 dict = presets_get_first_dict(presetsPlist);
374                 name = preset_get_name(dict);
375         }
376         else
377         {
378                 dict = presets_get_dict(presetsPlist, name);
379         }
380         if (dict == NULL || name == NULL)
381         {
382                 preset_to_ui(ud, NULL);
383         }
384         else
385         {
386                 preset_to_ui(ud, dict);
387                 ghb_settings_set_string(ud->settings, "preset", name);
388         }
389 }
390
391 void
392 ghb_update_from_preset(
393         signal_user_data_t *ud, 
394         const gchar *name, 
395         const gchar *key)
396 {
397         const GValue *gval;
398         
399         g_debug("ghb_update_from_preset() %s %s", name, key);
400         if (name == NULL) return;
401         gval = preset_get_value(name, key);
402         if (gval != NULL)
403         {
404                 ghb_ui_update(ud, key, gval);
405         }
406 }
407
408 gchar*
409 ghb_get_user_config_dir()
410 {
411         const gchar *dir;
412         gchar *config;
413
414         dir = g_get_user_config_dir();
415         if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
416         {
417                 dir = g_get_home_dir();
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         else
423         {
424                 config = g_strdup_printf ("%s/ghb", dir);
425                 if (!g_file_test(config, G_FILE_TEST_IS_DIR))
426                         g_mkdir (config, 0755);
427         }
428         return config;
429 }
430
431 static void
432 store_plist(GValue *plist, const gchar *name)
433 {
434         gchar *config, *path;
435         FILE *file;
436
437         config = ghb_get_user_config_dir();
438         path = g_strdup_printf ("%s/%s", config, name);
439         file = g_fopen(path, "w");
440         g_free(config);
441         g_free(path);
442         ghb_plist_write(file, plist);
443         fclose(file);
444 }
445
446 static GValue*
447 load_plist(const gchar *name)
448 {
449         gchar *config, *path;
450         GValue *plist = NULL;
451
452         config = ghb_get_user_config_dir();
453         path = g_strdup_printf ("%s/%s", config, name);
454         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
455         {
456                 plist = ghb_plist_parse_file(path);
457         }
458         g_free(config);
459         g_free(path);
460         return plist;
461 }
462
463 static void
464 remove_plist(const gchar *name)
465 {
466         gchar *config, *path;
467
468         config = ghb_get_user_config_dir();
469         path = g_strdup_printf ("%s/%s", config, name);
470         if (g_file_test(path, G_FILE_TEST_IS_REGULAR))
471         {
472                 g_unlink(path);
473         }
474         g_free(path);
475         g_free(config);
476 }
477
478 static gboolean prefs_initializing = FALSE;
479
480 void
481 ghb_prefs_to_ui(signal_user_data_t *ud)
482 {
483         const GValue *gval;
484         gchar *key;
485         gchar *str;
486         GValue *internal, *dict;
487         GHashTableIter iter;
488         
489
490         prefs_initializing = TRUE;
491
492         // Setting a ui widget will cause the corresponding setting
493         // to be set, but it also triggers a callback that can 
494         // have the side effect of using other settings values
495         // that have not yet been set.  So set *all* settings first
496         // then update the ui.
497         internal = plist_get_dict(internalPlist, "Initialization");
498         ghb_dict_iter_init(&iter, internal);
499         // middle (void*) cast prevents gcc warning "defreferencing type-punned
500         // pointer will break strict-aliasing rules"
501         while (g_hash_table_iter_next(
502                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
503         {
504                 ghb_ui_update(ud, key, gval);
505         }
506
507         dict = plist_get_dict(prefsPlist, "Preferences");
508         internal = plist_get_dict(internalPlist, "Preferences");
509         ghb_dict_iter_init(&iter, internal);
510         // middle (void*) cast prevents gcc warning "defreferencing type-punned
511         // pointer will break strict-aliasing rules"
512         while (g_hash_table_iter_next(
513                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
514     {
515                 const GValue *value = NULL;
516                 if (dict)
517                         value = ghb_dict_lookup(dict, key);
518                 if (value == NULL)
519                         value = gval;
520                 ghb_settings_set_value(ud->settings, key, value);
521     }
522         internal = plist_get_dict(internalPlist, "Preferences");
523         ghb_dict_iter_init(&iter, internal);
524         // middle (void*) cast prevents gcc warning "defreferencing type-punned
525         // pointer will break strict-aliasing rules"
526         while (g_hash_table_iter_next(
527                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
528         {
529                 const GValue *value = NULL;
530                 if (dict)
531                         value = ghb_dict_lookup(dict, key);
532                 if (value == NULL)
533                         value = gval;
534                 ghb_ui_update(ud, key, value);
535         }
536         const GValue *val;
537         val = ghb_settings_get_value(ud->settings, "show_presets");
538         ghb_ui_update(ud, "show_presets", val);
539         if (ghb_settings_get_boolean(ud->settings, "hbfd_feature"))
540         {
541                 GtkAction *action;
542                 val = ghb_settings_get_value(ud->settings, "hbfd");
543                 ghb_ui_update(ud, "hbfd", val);
544                 action = GHB_ACTION (ud->builder, "hbfd");
545                 gtk_action_set_visible(action, TRUE);
546         }
547         else
548         {
549                 ghb_ui_update(ud, "hbfd", ghb_int64_value(0));
550         }
551         gval = ghb_settings_get_value(ud->settings, "default_source");
552         ghb_settings_set_value (ud->settings, "source", gval);
553         str = ghb_settings_get_string(ud->settings, "destination_dir");
554
555         gchar *path = g_strdup_printf ("%s/new_video.mp4", str);
556         ghb_ui_update(ud, "destination", ghb_string_value(path));
557         g_free(str);
558         g_free(path);
559
560         prefs_initializing = FALSE;
561 }
562
563 void
564 ghb_prefs_save(GValue *settings)
565 {
566         GValue *dict;
567         GValue *pref_dict;
568         GHashTableIter iter;
569         gchar *key;
570         const GValue *value;
571         
572         if (prefs_initializing) return;
573         dict = plist_get_dict(internalPlist, "Preferences");
574         if (dict == NULL) return;
575         pref_dict = plist_get_dict(prefsPlist, "Preferences");
576         if (pref_dict == NULL) return;
577         ghb_dict_iter_init(&iter, dict);
578         // middle (void*) cast prevents gcc warning "defreferencing type-punned
579         // pointer will break strict-aliasing rules"
580         while (g_hash_table_iter_next(
581                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
582     {
583             value = ghb_settings_get_value(settings, key);
584             if (value != NULL)
585             {
586                         ghb_dict_insert(pref_dict, g_strdup(key), ghb_value_dup(value));
587             }
588         }
589     store_plist(prefsPlist, "preferences");
590 }
591
592 void
593 ghb_pref_save(GValue *settings, const gchar *key)
594 {
595         const GValue *value;
596         
597         if (prefs_initializing) return;
598         value = ghb_settings_get_value(settings, key);
599         if (value != NULL)
600         {
601                 GValue *dict;
602                 dict = plist_get_dict(prefsPlist, "Preferences");
603                 if (dict == NULL) return;
604                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
605                 store_plist(prefsPlist, "preferences");
606         }
607 }
608
609 void
610 ghb_settings_init(signal_user_data_t *ud)
611 {
612         GValue *internal;
613         GHashTableIter iter;
614         gchar *key;
615         GValue *gval;
616
617
618         g_debug("ghb_settings_init");
619         prefs_initializing = TRUE;
620
621         internalPlist = ghb_resource_get("internal-defaults");
622         // Setting a ui widget will cause the corresponding setting
623         // to be set, but it also triggers a callback that can 
624         // have the side effect of using other settings values
625         // that have not yet been set.  So set *all* settings first
626         // then update the ui.
627         internal = plist_get_dict(internalPlist, "Initialization");
628         ghb_dict_iter_init(&iter, internal);
629         // middle (void*) cast prevents gcc warning "defreferencing type-punned
630         // pointer will break strict-aliasing rules"
631         while (g_hash_table_iter_next(
632                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
633         {
634                 ghb_settings_set_value(ud->settings, key, gval);
635         }
636
637         internal = plist_get_dict(internalPlist, "Presets");
638         ghb_dict_iter_init(&iter, internal);
639         // middle (void*) cast prevents gcc warning "defreferencing type-punned
640         // pointer will break strict-aliasing rules"
641         while (g_hash_table_iter_next(
642                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
643         {
644                 ghb_settings_set_value(ud->settings, key, gval);
645         }
646
647         internal = plist_get_dict(internalPlist, "Preferences");
648         ghb_dict_iter_init(&iter, internal);
649         // middle (void*) cast prevents gcc warning "defreferencing type-punned
650         // pointer will break strict-aliasing rules"
651         while (g_hash_table_iter_next(
652                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
653         {
654                 ghb_settings_set_value(ud->settings, key, gval);
655         }
656         prefs_initializing = FALSE;
657 }
658
659 void
660 ghb_settings_close()
661 {
662         if (internalPlist)
663                 ghb_value_free(internalPlist);
664         if (presetsPlist)
665                 ghb_value_free(presetsPlist);
666         if (prefsPlist)
667                 ghb_value_free(prefsPlist);
668 }
669
670 void
671 ghb_prefs_load(signal_user_data_t *ud)
672 {
673         GValue *dict, *internal;
674         GHashTableIter iter;
675         gchar *key;
676         GValue *gval;
677         
678         g_debug("ghb_prefs_load");
679         prefsPlist = load_plist("preferences");
680         if (prefsPlist == NULL)
681                 prefsPlist = ghb_dict_value_new();
682         dict = plist_get_dict(prefsPlist, "Preferences");
683         internal = plist_get_dict(internalPlist, "Preferences");
684     if (dict == NULL && internal)
685     {
686                 dict = ghb_dict_value_new();
687                 ghb_dict_insert(prefsPlist, g_strdup("Preferences"), dict);
688
689         // Get defaults from internal defaults 
690                 ghb_dict_iter_init(&iter, internal);
691                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
692                 // pointer will break strict-aliasing rules"
693                 while (g_hash_table_iter_next(
694                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&gval))
695         {
696                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
697         }
698                 const gchar *dir = g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS);
699                 if (dir == NULL)
700                 {
701                         dir = ".";
702                 }
703                 ghb_dict_insert(dict, 
704                         g_strdup("destination_dir"), ghb_value_dup(ghb_string_value(dir)));
705                 store_plist(prefsPlist, "preferences");
706     }
707 }
708
709 void
710 ghb_presets_reload(signal_user_data_t *ud)
711 {
712         GValue *std_presets;
713         gint count, ii;
714
715         g_debug("ghb_presets_reload()\n");
716         std_presets = ghb_resource_get("standard-presets");
717         if (std_presets == NULL) return;
718
719         // Merge the keyfile contents into our presets
720         count = ghb_array_len(std_presets);
721         for (ii = 0; ii < count; ii++)
722         {
723                 const gchar *name;
724                 GValue *std_dict;
725                 GValue *copy_dict;
726                 GHashTableIter iter;
727                 gchar *key;
728                 GValue *value;
729                 gint pos;
730
731                 std_dict = ghb_array_get_nth(std_presets, ii);
732                 name = preset_get_name(std_dict);
733                 presets_remove(presetsPlist, name);
734
735                 copy_dict = ghb_dict_value_new();
736                 pos = presets_find_pos(presetsPlist, name, 0);
737                 ghb_array_insert(presetsPlist, pos, copy_dict);
738                 ghb_dict_iter_init(&iter, std_dict);
739                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
740                 // pointer will break strict-aliasing rules"
741                 while (g_hash_table_iter_next(
742                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
743                 {
744                         ghb_dict_insert(copy_dict, g_strdup(key), ghb_value_dup(value));
745                 }
746         }
747         store_plist(presetsPlist, "presets");
748 }
749
750 static void
751 presets_store()
752 {
753         g_debug("presets_store ()\n");
754         store_plist(presetsPlist, "presets");
755 }
756
757 void
758 ghb_save_queue(GValue *queue)
759 {
760         store_plist(queue, "queue");
761 }
762
763 GValue*
764 ghb_load_queue()
765 {
766         return load_plist("queue");
767 }
768
769 void
770 ghb_remove_queue_file()
771 {
772         remove_plist("queue");
773 }
774
775 void
776 ghb_presets_load()
777 {
778         presetsPlist = load_plist("presets");
779         if (presetsPlist == NULL)
780         {
781                 presetsPlist = ghb_value_dup(ghb_resource_get("standard-presets"));
782                 presets_store();
783         }
784         if (G_VALUE_TYPE(presetsPlist) == ghb_dict_get_type())
785         { // Presets is older dictionary format. Convert to array
786                 GHashTableIter old_iter;
787                 GValue *presets;
788                 gchar *name;
789                 GValue *orig_dict;
790
791                 presets = ghb_array_value_new(32);
792                 ghb_dict_iter_init(&old_iter, presetsPlist);
793                 // middle (void*) cast prevents gcc warning "defreferencing type-punned
794                 // pointer will break strict-aliasing rules"
795                 while (g_hash_table_iter_next(
796                         &old_iter, (gpointer*)(void*)&name, (gpointer*)(void*)&orig_dict))
797                 {
798                         GHashTableIter iter;
799                         gchar *key;
800                         GValue *value, *dict;
801
802                         dict = ghb_dict_value_new();
803                         ghb_dict_insert(dict, g_strdup("preset_name"), 
804                                 ghb_string_value_new(name));
805                         ghb_array_append(presets, dict);
806                         ghb_dict_iter_init(&iter, orig_dict);
807                         // middle (void*) cast prevents gcc warning "defreferencing 
808                         // type-punned pointer will break strict-aliasing rules"
809                         while (g_hash_table_iter_next(
810                                 &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
811                         {
812                                 ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(value));
813                         }
814                 }
815                 ghb_value_free(presetsPlist);
816                 presetsPlist = presets;
817                 presets_store();
818         }
819 }
820
821 void
822 ghb_settings_save(signal_user_data_t *ud, const gchar *name)
823 {
824         GValue *dict, *internal;
825         GHashTableIter iter;
826         gchar *key;
827         GValue *value;
828         gboolean autoscale;
829
830         if (internalPlist == NULL) return;
831         if (ghb_settings_get_boolean(ud->settings, "allow_tweaks"))
832         {
833                 gchar *str;
834                 str = ghb_settings_get_string(ud->settings, "tweak_deinterlace");
835                 if (str)
836                 {
837                         ghb_settings_set_string(ud->settings, "deinterlace", str);
838                         g_free(str);
839                 }
840                 str = ghb_settings_get_string(ud->settings, "tweak_denoise");
841                 if (str)
842                 {
843                         ghb_settings_set_string(ud->settings, "denoise", str);
844                         g_free(str);
845                 }
846         }
847         autoscale = ghb_settings_get_boolean(ud->settings, "autoscale");
848         ghb_settings_set_int64(ud->settings, "preset_type", 1);
849
850         dict = ghb_dict_value_new();
851         ghb_dict_insert(dict, g_strdup("preset_name"), ghb_string_value_new(name));
852         gint pos = presets_find_pos(presetsPlist, name, 1);
853         ghb_array_insert(presetsPlist, pos, dict);
854         internal = plist_get_dict(internalPlist, "Presets");
855
856         ghb_dict_iter_init(&iter, internal);
857         // middle (void*) cast prevents gcc warning "defreferencing type-punned
858         // pointer will break strict-aliasing rules"
859         while (g_hash_table_iter_next(
860                         &iter, (gpointer*)(void*)&key, (gpointer*)(void*)&value))
861         {
862                 const GValue *gval;
863                 gchar *key2;
864
865                 key2 = key;
866                 if (!autoscale)
867                 {
868                         if (strcmp(key, "max_width") == 0)
869                         {
870                                 key2 = "scale_width";
871                         }
872                         else if (strcmp(key, "max_height") == 0)
873                         {
874                                 key2 = "scale_height";
875                         }
876                 }
877                 gval = ghb_settings_get_value(ud->settings, key2);
878                 if (gval == NULL)
879                 {
880                         g_debug("Setting (%s) is not in defaults\n", (gchar*)key);
881                         continue;
882                 }
883                 if (ghb_value_cmp(gval, value) != 0)
884                 {
885                         // Differs from default value.  Store it.
886                         ghb_dict_insert(dict, g_strdup(key), ghb_value_dup(gval));
887                 }
888         }
889         presets_store();
890         ud->dont_clear_presets = TRUE;
891         ghb_set_preset (ud, name);
892         ud->dont_clear_presets = FALSE;
893 }
894
895 void
896 ghb_presets_remove(const gchar *name)
897 {
898         if (presets_get_dict(presetsPlist, name))
899         {
900                 presets_remove(presetsPlist, name);
901                 presets_store();
902         }
903 }
904
905 void
906 ghb_presets_list_update(signal_user_data_t *ud)
907 {
908         GtkTreeView *treeview;
909         GtkTreeIter iter;
910         GtkTreeStore *store;
911         gboolean done;
912         const gchar *preset;
913         gchar *def_preset;
914         const gchar *description;
915         gint flags, custom, def;
916         gint count, ii;
917         GValue *dict;
918         
919         g_debug("ghb_presets_list_update ()");
920         def_preset = ghb_settings_get_string(ud->settings, "default_preset");
921         count = ghb_array_len(presetsPlist);
922         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
923         store = GTK_TREE_STORE(gtk_tree_view_get_model(treeview));
924         ii = 0;
925         if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
926         {
927                 do
928                 {
929                         if (ii < count)
930                         {
931                                 // Update row with settings data
932                                 g_debug("Updating row");
933                                 dict = ghb_array_get_nth(presetsPlist, ii);
934                                 preset = preset_get_name(dict);
935                                 def = 0;
936                                 if (strcmp(preset, def_preset) == 0)
937                                         def = PRESET_DEFAULT;
938                                 
939                                 description = ghb_presets_get_description(dict);
940                                 flags = ghb_preset_flags(dict);
941                                 custom = flags & PRESET_CUSTOM;
942                                 gtk_tree_store_set(store, &iter, 
943                                                         0, preset, 
944                                                         1, def ? 800 : 400, 
945                                                         2, def ? 2 : 0,
946                                                         3, custom ? "black" : "blue", 
947                                                         4, description,
948                                                         -1);
949                                 ii++;
950                                 done = !gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
951                         }
952                         else
953                         {
954                                 // No more settings data, remove row
955                                 g_debug("Removing row");
956                                 done = !gtk_tree_store_remove(store, &iter);
957                         }
958                 } while (!done);
959         }
960         while (ii < count)
961         {
962                 // Additional settings, add row
963                 g_debug("Adding rows");
964                 dict = ghb_array_get_nth(presetsPlist, ii);
965                 preset = preset_get_name(dict);
966                 def = 0;
967                 if (strcmp(preset, def_preset) == 0)
968                         def = PRESET_DEFAULT;
969
970                 description = ghb_presets_get_description(dict);
971                 gtk_tree_store_append(store, &iter, NULL);
972                 flags = ghb_preset_flags(dict);
973                 custom = flags & PRESET_CUSTOM;
974                 gtk_tree_store_set(store, &iter, 0, preset, 
975                                                         1, def ? 800 : 400, 
976                                                         2, def ? 2 : 0,
977                                                         3, custom ? "black" : "blue", 
978                                                         4, description,
979                                                         -1);
980                 ii++;
981         }
982         g_free(def_preset);
983 }
984
985 void
986 ghb_select_preset(GtkBuilder *builder, const gchar *preset)
987 {
988         GtkTreeView *treeview;
989         GtkTreeSelection *selection;
990         GtkTreeModel *store;
991         GtkTreeIter iter;
992         gchar *tpreset;
993         gboolean done;
994         gboolean foundit = FALSE;
995         
996         g_debug("select_preset()");
997         if (preset == NULL) return;
998         treeview = GTK_TREE_VIEW(GHB_WIDGET(builder, "presets_list"));
999         selection = gtk_tree_view_get_selection (treeview);
1000         store = gtk_tree_view_get_model (treeview);
1001         if (gtk_tree_model_get_iter_first(store, &iter))
1002         {
1003                 do
1004                 {
1005                         gtk_tree_model_get(store, &iter, 0, &tpreset, -1);
1006                         if (strcmp(preset, tpreset) == 0)
1007                         {
1008                                 gtk_tree_selection_select_iter (selection, &iter);
1009                                 foundit = TRUE;
1010                                 g_free(tpreset);
1011                                 break;
1012                         }
1013                         g_free(tpreset);
1014                         done = !gtk_tree_model_iter_next(store, &iter);
1015                 } while (!done);
1016         }
1017         if (!foundit)
1018         {
1019                 gtk_tree_model_get_iter_first(store, &iter);
1020                 gtk_tree_selection_select_iter (selection, &iter);
1021         }
1022 }
1023
1024 static void
1025 update_audio_presets(signal_user_data_t *ud)
1026 {
1027         g_debug("update_audio_presets");
1028         const GValue *audio_list;
1029
1030         audio_list = ghb_settings_get_value(ud->settings, "audio_list");
1031         ghb_settings_set_value(ud->settings, "pref_audio_list", audio_list);
1032 }
1033
1034 void
1035 presets_save_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1036 {
1037         GtkWidget *dialog;
1038         GtkEntry *entry;
1039         GtkTextView *desc;
1040         GtkResponseType response;
1041         gchar *preset;
1042
1043         g_debug("presets_save_clicked_cb ()");
1044         preset = ghb_settings_get_string (ud->settings, "preset");
1045         // Clear the description
1046         desc = GTK_TEXT_VIEW(GHB_WIDGET(ud->builder, "preset_description"));
1047         dialog = GHB_WIDGET(ud->builder, "preset_save_dialog");
1048         entry = GTK_ENTRY(GHB_WIDGET(ud->builder, "preset_name"));
1049         gtk_entry_set_text(entry, preset);
1050         g_free(preset);
1051         response = gtk_dialog_run(GTK_DIALOG(dialog));
1052         gtk_widget_hide(dialog);
1053         if (response == GTK_RESPONSE_OK)
1054         {
1055                 // save the preset
1056                 const gchar *name = gtk_entry_get_text(entry);
1057                 g_debug("description to settings");
1058                 ghb_widget_to_setting(ud->settings, GTK_WIDGET(desc));
1059                 // Construct the audio settings presets from the current audio list
1060                 update_audio_presets(ud);
1061                 ghb_settings_save(ud, name);
1062                 ghb_presets_list_update(ud);
1063                 // Make the new preset the selected item
1064                 ghb_select_preset(ud->builder, name);
1065         }
1066 }
1067
1068 void
1069 presets_restore_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1070 {
1071         g_debug("presets_restore_clicked_cb ()");
1072         // Reload only the standard presets
1073         ghb_presets_reload(ud);
1074         ghb_presets_list_update(ud);
1075         // Updating the presets list shuffles things around
1076         // need to make sure the proper preset is selected
1077         gchar *preset = ghb_settings_get_string (ud->settings, "preset");
1078         ghb_select_preset(ud->builder, preset);
1079         g_free(preset);
1080 }
1081
1082 void
1083 presets_remove_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1084 {
1085         GtkTreeView *treeview;
1086         GtkTreeSelection *selection;
1087         GtkTreeModel *store;
1088         GtkTreeIter iter;
1089         gchar *preset;
1090         GtkResponseType response;
1091
1092         g_debug("presets_remove_clicked_cb ()");
1093         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1094         selection = gtk_tree_view_get_selection (treeview);
1095         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1096         {
1097                 GtkWidget *dialog;
1098
1099                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1100                 dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
1101                                                                 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
1102                                                                 "Confirm deletion of preset %s.", preset);
1103                 response = gtk_dialog_run(GTK_DIALOG(dialog));
1104                 gtk_widget_destroy (dialog);
1105                 if (response == GTK_RESPONSE_YES)
1106                 {
1107                         GtkTreeIter nextIter = iter;
1108                         gchar *nextPreset = NULL;
1109                         if (!gtk_tree_model_iter_next(store, &nextIter))
1110                         {
1111                                 if (gtk_tree_model_get_iter_first(store, &nextIter))
1112                                 {
1113                                         gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1114                                 }
1115                         }
1116                         else
1117                         {
1118                                 gtk_tree_model_get(store, &nextIter, 0, &nextPreset, -1);
1119                         }
1120                         // Remove the selected item
1121                         // First unselect it so that selecting the new item works properly
1122                         gtk_tree_selection_unselect_iter (selection, &iter);
1123                         ghb_presets_remove(preset);
1124                         ghb_presets_list_update(ud);
1125                         ghb_select_preset(ud->builder, nextPreset);
1126                 }
1127         }
1128 }
1129
1130 static void
1131 preset_update_title_deps(signal_user_data_t *ud, ghb_title_info_t *tinfo)
1132 {
1133         GtkWidget *widget;
1134
1135         ghb_ui_update(ud, "scale_width", 
1136                         ghb_int64_value(tinfo->width - tinfo->crop[2] - tinfo->crop[3]));
1137         // If anamorphic or keep_aspect, the hight will be automatically calculated
1138         gboolean keep_aspect, anamorphic;
1139         keep_aspect = ghb_settings_get_boolean(ud->settings, "keep_aspect");
1140         anamorphic = ghb_settings_get_boolean(ud->settings, "anamorphic");
1141         if (!(keep_aspect || anamorphic))
1142         {
1143                 ghb_ui_update(ud, "scale_height", 
1144                         ghb_int64_value(tinfo->height - tinfo->crop[0] - tinfo->crop[1]));
1145         }
1146
1147         // Set the limits of cropping.  hb_set_anamorphic_size crashes if
1148         // you pass it a cropped width or height == 0.
1149         gint bound;
1150         bound = tinfo->height / 2 - 2;
1151         widget = GHB_WIDGET (ud->builder, "crop_top");
1152         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1153         widget = GHB_WIDGET (ud->builder, "crop_bottom");
1154         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1155         bound = tinfo->width / 2 - 2;
1156         widget = GHB_WIDGET (ud->builder, "crop_left");
1157         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1158         widget = GHB_WIDGET (ud->builder, "crop_right");
1159         gtk_spin_button_set_range (GTK_SPIN_BUTTON(widget), 0, bound);
1160         if (ghb_settings_get_boolean(ud->settings, "autocrop"))
1161         {
1162                 ghb_ui_update(ud, "crop_top", ghb_int64_value(tinfo->crop[0]));
1163                 ghb_ui_update(ud, "crop_bottom", ghb_int64_value(tinfo->crop[1]));
1164                 ghb_ui_update(ud, "crop_left", ghb_int64_value(tinfo->crop[2]));
1165                 ghb_ui_update(ud, "crop_right", ghb_int64_value(tinfo->crop[3]));
1166         }
1167 }
1168
1169 void
1170 presets_list_selection_changed_cb(GtkTreeSelection *selection, signal_user_data_t *ud)
1171 {
1172         GtkTreeModel *store;
1173         GtkTreeIter iter;
1174         gchar *preset;
1175         ghb_title_info_t tinfo;
1176         GtkWidget *widget;
1177         
1178         g_debug("presets_list_selection_changed_cb ()");
1179         widget = GHB_WIDGET (ud->builder, "presets_remove");
1180         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1181         {
1182                 gtk_tree_model_get(store, &iter, 0, &preset, -1);
1183                 ud->dont_clear_presets = TRUE;
1184                 // Temporarily set the video_quality range to (0,100)
1185                 // This is needed so the video_quality value does not get
1186                 // truncated when set.  The range will be readjusted below
1187                 GtkWidget *qp = GHB_WIDGET(ud->builder, "video_quality");
1188                 gtk_range_set_range (GTK_RANGE(qp), 0, 100);
1189                 // Clear the audio list prior to changing the preset.  Existing audio
1190                 // can cause the container extension to be automatically changed when
1191                 // it shouldn't be
1192                 ghb_clear_audio_list(ud);
1193                 ghb_set_preset(ud, preset);
1194                 gint titleindex;
1195                 titleindex = ghb_settings_combo_int(ud->settings, "title");
1196                 ghb_set_pref_audio(titleindex, ud);
1197                 ghb_settings_set_boolean(ud->settings, "preset_modified", FALSE);
1198                 ud->dont_clear_presets = FALSE;
1199                 if (ghb_get_title_info (&tinfo, titleindex))
1200                 {
1201                         preset_update_title_deps(ud, &tinfo);
1202                 }
1203                 ghb_set_scale (ud, GHB_SCALE_KEEP_NONE);
1204
1205                 gint vqmin, vqmax;
1206                 ghb_vquality_range(ud, &vqmin, &vqmax);
1207                 gtk_range_set_range (GTK_RANGE(qp), vqmin, vqmax);
1208                 gtk_widget_set_sensitive(widget, TRUE);
1209         }
1210         else
1211         {
1212                 g_debug("No selection???  Perhaps unselected.");
1213                 gtk_widget_set_sensitive(widget, FALSE);
1214         }
1215 }
1216
1217 void
1218 ghb_clear_presets_selection(signal_user_data_t *ud)
1219 {
1220         GtkTreeView *treeview;
1221         GtkTreeSelection *selection;
1222         
1223         if (ud->dont_clear_presets) return;
1224         g_debug("ghb_clear_presets_selection()");
1225         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1226         selection = gtk_tree_view_get_selection (treeview);
1227         gtk_tree_selection_unselect_all (selection);
1228         ghb_settings_set_boolean(ud->settings, "preset_modified", TRUE);
1229 }
1230
1231 void
1232 presets_frame_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation, signal_user_data_t *ud)
1233 {
1234         GtkTreeView *treeview;
1235         GtkTreeSelection *selection;
1236         GtkTreeModel *store;
1237         GtkTreeIter iter;
1238         
1239         treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "presets_list"));
1240         selection = gtk_tree_view_get_selection(treeview);
1241         if (gtk_tree_selection_get_selected(selection, &store, &iter))
1242         {
1243                 GtkTreePath *path;
1244                 path = gtk_tree_model_get_path (store, &iter);
1245                 // Make the parent visible in scroll window if it is not.
1246                 gtk_tree_view_scroll_to_cell (treeview, path, NULL, FALSE, 0, 0);
1247                 gtk_tree_path_free(path);
1248         }
1249 }
1250
1251 void
1252 presets_default_clicked_cb(GtkWidget *xwidget, signal_user_data_t *ud)
1253 {
1254         ghb_set_preset_default(ud->settings);
1255         ghb_presets_list_update(ud);
1256 }
1257