]> granicus.if.org Git - handbrake/commitdiff
LinGui: change language lists from GtkListBox to GtkTreeView
authorJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 12 Jun 2018 19:09:59 +0000 (12:09 -0700)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Tue, 12 Jun 2018 19:09:59 +0000 (12:09 -0700)
The GtkTreeView is more flexible and more capable.  Languages can be
searched for in the GtkTreeView by focusing the widget and typing what
you want to find.  Double clicking an item in the list will add or
remove it from the "selected" languages list in audio and subtitle track
selection settings.

gtk/src/audiohandler.c
gtk/src/audiohandler.h
gtk/src/ghb.m4
gtk/src/hb-backend.c
gtk/src/hb-backend.h
gtk/src/subtitlehandler.c

index d4994463fbc0d780bb67d5110e9e0fd26bcdf8f8..68a45ebe8bda40bc06326d7264b59429d8f8ab83 100644 (file)
@@ -1986,70 +1986,154 @@ audio_def_setting_update(signal_user_data_t *ud, GtkWidget *widget)
     }
 }
 
+void
+audio_add_lang_iter(GtkTreeModel *tm, GtkTreeIter *iter, signal_user_data_t *ud)
+{
+    GtkTreeView         * selected;
+    GtkTreeStore        * selected_ts;
+    GtkTreeIter           pos;
+    GtkTreePath         * tp;
+    char                * lang;
+    int                   index;
+    const iso639_lang_t * iso_lang;
+    GhbValue            * glang, * alang_list;
+    GtkTreeSelection    * tsel;
+
+    selected    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_selected_lang"));
+    selected_ts = GTK_TREE_STORE(gtk_tree_view_get_model(selected));
+    tsel        = gtk_tree_view_get_selection(selected);
+
+    // Add to UI selected language list box
+    gtk_tree_model_get(tm, iter, 0, &lang, 1, &index, -1);
+    gtk_tree_store_append(selected_ts, &pos, NULL);
+    gtk_tree_store_set(selected_ts, &pos, 0, lang, 1, index, -1);
+    g_free(lang);
+
+    // Select the item added to the selected list and make it
+    // visible in the scrolled window
+    tp = gtk_tree_model_get_path(GTK_TREE_MODEL(selected_ts), &pos);
+    gtk_tree_selection_select_iter(tsel, &pos);
+    gtk_tree_view_scroll_to_cell(selected, tp, NULL, FALSE, 0, 0);
+    gtk_tree_path_free(tp);
+
+    // Remove from UI available language list box
+    gtk_tree_store_remove(GTK_TREE_STORE(tm), iter);
+
+    // Add to preset language list
+    iso_lang = ghb_iso639_lookup_by_int(index);
+    glang = ghb_string_value_new(iso_lang->iso639_2);
+    alang_list = ghb_dict_get_value(ud->settings, "AudioLanguageList");
+    ghb_array_append(alang_list, glang);
+    ghb_clear_presets_selection(ud);
+}
+
+G_MODULE_EXPORT void
+audio_avail_lang_activated_cb(GtkTreeView *tv, GtkTreePath *tp,
+                              GtkTreeViewColumn *column, signal_user_data_t *ud)
+{
+    GtkTreeIter    iter;
+    GtkTreeModel * tm = gtk_tree_view_get_model(tv);
+
+    if (gtk_tree_model_get_iter(tm, &iter, tp))
+    {
+        audio_add_lang_iter(tm, &iter, ud);
+    }
+}
+
 G_MODULE_EXPORT void
 audio_add_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
 {
-    GtkListBox *avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_avail_lang"));
-    GtkListBox *selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_selected_lang"));
-    GtkListBoxRow *row;
-    GtkWidget *label;
+    GtkTreeView      * avail;
+    GtkTreeModel     * avail_tm;
+    GtkTreeSelection * tsel;
+    GtkTreeIter        iter;
 
-    row = gtk_list_box_get_selected_row(avail);
-    if (row != NULL)
+    avail       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_avail_lang"));
+    avail_tm    = gtk_tree_view_get_model(avail);
+    tsel        = gtk_tree_view_get_selection(avail);
+    if (gtk_tree_selection_get_selected(tsel, NULL, &iter))
     {
-        int idx;
-        const iso639_lang_t *lang;
-        GhbValue *glang, *alang_list;
+        audio_add_lang_iter(avail_tm, &iter, ud);
+    }
+}
 
-        // Remove from UI available language list box
-        label = gtk_bin_get_child(GTK_BIN(row));
-        g_object_ref(G_OBJECT(label));
-        gtk_widget_destroy(GTK_WIDGET(row));
-        gtk_widget_show(label);
-        // Add to UI selected language list box
-        gtk_list_box_insert(selected, label, -1);
+void
+audio_remove_lang_iter(GtkTreeModel *tm, GtkTreeIter *iter,
+                       signal_user_data_t *ud)
+{
+    GtkTreeView      * avail;
+    GtkTreeStore     * avail_ts;
+    GtkTreeIter        pos, sibling;
+    char             * lang;
+    int                index;
+    GtkTreePath      * tp  = gtk_tree_model_get_path(tm, iter);
+    int              * ind = gtk_tree_path_get_indices(tp);
+    int                row = ind[0];
+    GhbValue         * alang_list;
+    GtkTreeSelection * tsel;
+
+    gtk_tree_path_free(tp);
+    avail    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_avail_lang"));
+    avail_ts = GTK_TREE_STORE(gtk_tree_view_get_model(avail));
+    tsel     = gtk_tree_view_get_selection(avail);
 
-        // Add to preset language list
-        idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-        lang = ghb_iso639_lookup_by_int(idx);
-        glang = ghb_string_value_new(lang->iso639_2);
-        alang_list = ghb_dict_get_value(ud->settings, "AudioLanguageList");
-        ghb_array_append(alang_list, glang);
-        ghb_clear_presets_selection(ud);
+    // Add to UI available language list box
+    gtk_tree_model_get(tm, iter, 0, &lang, 1, &index, -1);
+    if (ghb_find_lang_row(GTK_TREE_MODEL(avail_ts), &sibling, index))
+    {
+        gtk_tree_store_insert_before(avail_ts, &pos, NULL, &sibling);
     }
+    else
+    {
+        gtk_tree_store_append(avail_ts, &pos, NULL);
+    }
+    gtk_tree_store_set(avail_ts, &pos, 0, lang, 1, index, -1);
+    g_free(lang);
+
+    // Select the item added to the available list and make it
+    // visible in the scrolled window
+    tp = gtk_tree_model_get_path(GTK_TREE_MODEL(avail_ts), &pos);
+    gtk_tree_selection_select_iter(tsel, &pos);
+    gtk_tree_view_scroll_to_cell(avail, tp, NULL, FALSE, 0, 0);
+    gtk_tree_path_free(tp);
+
+    // Remove from UI selected language list box
+    gtk_tree_store_remove(GTK_TREE_STORE(tm), iter);
+
+    // Remove from preset language list
+    alang_list = ghb_dict_get_value(ud->settings, "AudioLanguageList");
+    ghb_array_remove(alang_list, row);
+    ghb_clear_presets_selection(ud);
 }
 
 G_MODULE_EXPORT void
-audio_remove_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+audio_selected_lang_activated_cb(GtkTreeView *tv, GtkTreePath *tp,
+                                 GtkTreeViewColumn *column,
+                                 signal_user_data_t *ud)
 {
+    GtkTreeIter    iter;
+    GtkTreeModel * tm = gtk_tree_view_get_model(tv);
 
-    GtkListBox *avail, *selected;
-    GtkListBoxRow *row;
-    GtkWidget *label;
-
-    avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_avail_lang"));
-    selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_selected_lang"));
-    row = gtk_list_box_get_selected_row(selected);
-    if (row != NULL)
+    if (gtk_tree_model_get_iter(tm, &iter, tp))
     {
-        gint index;
-        GhbValue *alang_list;
-
-        index = gtk_list_box_row_get_index(row);
+        audio_remove_lang_iter(tm, &iter, ud);
+    }
+}
 
-        // Remove from UI selected language list box
-        label = gtk_bin_get_child(GTK_BIN(row));
-        g_object_ref(G_OBJECT(label));
-        int idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-        gtk_widget_destroy(GTK_WIDGET(row));
-        gtk_widget_show(label);
-        // Add to UI available language list box
-        gtk_list_box_insert(avail, label, idx);
+G_MODULE_EXPORT void
+audio_remove_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+    GtkTreeView      * selected;
+    GtkTreeModel     * selected_tm;
+    GtkTreeSelection * tsel;
+    GtkTreeIter        iter;
 
-        // Remove from preset language list
-        alang_list = ghb_dict_get_value(ud->settings, "AudioLanguageList");
-        ghb_array_remove(alang_list, index);
-        ghb_clear_presets_selection(ud);
+    selected    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_selected_lang"));
+    selected_tm = gtk_tree_view_get_model(selected);
+    tsel        = gtk_tree_view_get_selection(selected);
+    if (gtk_tree_selection_get_selected(tsel, NULL, &iter))
+    {
+        audio_remove_lang_iter(selected_tm, &iter, ud);
     }
 }
 
@@ -2297,54 +2381,73 @@ audio_def_encode_setting_changed_cb(GtkWidget *widget, signal_user_data_t *ud)
     ghb_clear_presets_selection(ud);
 }
 
-GtkListBoxRow* ghb_find_lang_row(GtkListBox *list_box, int lang_idx)
+gboolean ghb_find_lang_row(GtkTreeModel *model, GtkTreeIter *iter, int lang_idx)
 {
-    GList *list, *link;
-    GtkListBoxRow *result = NULL;
-
-    list = link = gtk_container_get_children(GTK_CONTAINER(list_box));
-    while (link != NULL)
+    if (gtk_tree_model_get_iter_first(model, iter))
     {
-        GtkListBoxRow *row = (GtkListBoxRow*)link->data;
-        GtkWidget *label = gtk_bin_get_child(GTK_BIN(row));
-        int idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-        if (idx == lang_idx)
+        do
         {
-            result = row;
-            break;
-        }
-        link = link->next;
-    }
-    g_list_free(list);
-
-    return result;
-}
+            gint          index;
 
-static void audio_def_lang_list_clear_cb(GtkWidget *row, gpointer data)
-{
-    GtkListBox *avail = (GtkListBox*)data;
-    GtkWidget *label = gtk_bin_get_child(GTK_BIN(row));
-    g_object_ref(G_OBJECT(label));
-    gtk_widget_destroy(GTK_WIDGET(row));
-    gtk_widget_show(label);
-    int idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-    gtk_list_box_insert(avail, label, idx);
+            gtk_tree_model_get(model, iter, 1, &index, -1);
+            if (index >= lang_idx)
+            {
+                return TRUE;
+            }
+        } while (gtk_tree_model_iter_next(model, iter));
+    }
+    return FALSE;
 }
 
 static void
 audio_def_selected_lang_list_clear(signal_user_data_t *ud)
 {
-    GtkListBox *avail, *selected;
-    avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_avail_lang"));
-    selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_selected_lang"));
-    gtk_container_foreach(GTK_CONTAINER(selected),
-                          audio_def_lang_list_clear_cb, (gpointer)avail);
+    GtkTreeView  * tv;
+    GtkTreeModel * selected_tm;
+    GtkTreeStore * avail_ts;
+    GtkTreeIter    iter;
+
+    tv          = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_avail_lang"));
+    avail_ts    = GTK_TREE_STORE(gtk_tree_view_get_model(tv));
+    tv          = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_selected_lang"));
+    selected_tm = gtk_tree_view_get_model(tv);
+    if (gtk_tree_model_get_iter_first(selected_tm, &iter))
+    {
+        do
+        {
+            gchar       * lang;
+            gint          index;
+            GtkTreeIter   pos, sibling;
+
+            gtk_tree_model_get(selected_tm, &iter, 0, &lang, 1, &index, -1);
+            if (ghb_find_lang_row(GTK_TREE_MODEL(avail_ts), &sibling, index))
+            {
+                gtk_tree_store_insert_before(avail_ts, &pos, NULL, &sibling);
+            }
+            else
+            {
+                gtk_tree_store_append(avail_ts, &pos, NULL);
+            }
+            gtk_tree_store_set(avail_ts, &pos, 0, lang, 1, index, -1);
+            g_free(lang);
+        } while (gtk_tree_model_iter_next(selected_tm, &iter));
+    }
+    gtk_tree_store_clear(GTK_TREE_STORE(selected_tm));
 }
 
 static void
 audio_def_lang_list_init(signal_user_data_t *ud)
 {
-    GhbValue *lang_list;
+    GhbValue     * lang_list;
+    GtkTreeView  * tv;
+    GtkTreeModel * avail;
+    GtkTreeStore * selected;
+    int            ii, count;
+
+    tv       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_avail_lang"));
+    avail    = gtk_tree_view_get_model(tv);
+    tv       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_selected_lang"));
+    selected = GTK_TREE_STORE(gtk_tree_view_get_model(tv));
 
     // Clear selected languages.
     audio_def_selected_lang_list_clear(ud);
@@ -2356,25 +2459,24 @@ audio_def_lang_list_init(signal_user_data_t *ud)
         ghb_dict_set(ud->settings, "AudioLanguageList", lang_list);
     }
 
-    int ii, count;
     count = ghb_array_len(lang_list);
     for (ii = 0; ii < count; )
     {
-        GhbValue *lang_val = ghb_array_get(lang_list, ii);
-        int idx = ghb_lookup_lang(lang_val);
+        GhbValue    * lang_val = ghb_array_get(lang_list, ii);
+        int           idx      = ghb_lookup_lang(lang_val);
+        GtkTreeIter   iter;
 
-        GtkListBox *avail, *selected;
-        GtkListBoxRow *row;
-        avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_avail_lang"));
-        selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_selected_lang"));
-        row = ghb_find_lang_row(avail, idx);
-        if (row)
+        if (ghb_find_lang_row(avail, &iter, idx))
         {
-            GtkWidget *label = gtk_bin_get_child(GTK_BIN(row));
-            g_object_ref(G_OBJECT(label));
-            gtk_widget_destroy(GTK_WIDGET(row));
-            gtk_widget_show(label);
-            gtk_list_box_insert(selected, label, -1);
+            gchar       * lang;
+            gint          index;
+            GtkTreeIter   pos;
+
+            gtk_tree_model_get(avail, &iter, 0, &lang, 1, &index, -1);
+            gtk_tree_store_append(selected, &pos, NULL);
+            gtk_tree_store_set(selected, &pos, 0, lang, 1, index, -1);
+            g_free(lang);
+            gtk_tree_store_remove(GTK_TREE_STORE(avail), &iter);
             ii++;
         }
         else
@@ -2427,10 +2529,12 @@ void ghb_audio_defaults_to_ui(signal_user_data_t *ud)
 
 void ghb_init_audio_defaults_ui(signal_user_data_t *ud)
 {
-    GtkListBox *list_box;
+    GtkTreeView * tv;
 
-    list_box = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "audio_avail_lang"));
-    ghb_init_lang_list_box(list_box);
+    tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_avail_lang"));
+    ghb_init_lang_list(tv, ud);
+    tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "audio_selected_lang"));
+    ghb_init_lang_list_model(tv);
 }
 
 G_MODULE_EXPORT void
index 45be4df0d2d3af227a138b3be2a2cb97f6a6764b..8c60f9e346efa0ad5cdaebe322d498853fa9e848 100644 (file)
@@ -40,7 +40,7 @@ void ghb_audio_list_refresh_all(signal_user_data_t *ud);
 char * ghb_format_quality( const char *prefix, int codec, double quality );
 void ghb_init_audio_defaults_ui(signal_user_data_t *ud);
 void ghb_audio_defaults_to_ui(signal_user_data_t *ud);
-GtkListBoxRow* ghb_find_lang_row(GtkListBox *list_box, int lang_idx);
+gboolean ghb_find_lang_row(GtkTreeModel *model, GtkTreeIter *iter, int idx);
 void ghb_audio_title_change(signal_user_data_t *ud, gboolean title_valid);
 void ghb_clear_audio_selection(GtkBuilder *builder);
 gboolean ghb_audio_quality_enabled(const GhbValue *asettings);
index c38eb13a31a676db5431ea5502199cfab4fd245b..c3d061f9a629bddace8cafb07bd1ed04bba683dd 100644 (file)
@@ -4265,10 +4265,12 @@ filter_output([
                                                 <property name="min_content_height">84</property>
                                                 <property name="vexpand">True</property>
                                                 <child>
-                                                  <object class="GtkListBox" id="audio_avail_lang">
+                                                  <object class="GtkTreeView" id="audio_avail_lang">
                                                     <property name="visible">True</property>
+                                                    <property name="headers-visible">False</property>
                                                     <property name="can_focus">True</property>
                                                     <property name="vexpand">True</property>
+                                                    <signal name="row-activated" handler="audio_avail_lang_activated_cb" swapped="no"/>
                                                   </object>
                                                 </child>
                                               </object>
@@ -4286,11 +4288,13 @@ filter_output([
                                                 <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
                                                 <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
                                                 <child>
-                                                  <object class="GtkListBox" id="audio_selected_lang">
+                                                  <object class="GtkTreeView" id="audio_selected_lang">
                                                     <property name="visible">True</property>
+                                                    <property name="headers-visible">False</property>
                                                     <property name="can_focus">True</property>
                                                     <property name="tooltip_text" translatable="yes">Create a list of languages you would like to select audio for.
 Tracks matching these languages will be selected using the chosen Selection Behavior.</property>
+                                                    <signal name="row-activated" handler="audio_selected_lang_activated_cb" swapped="no"/>
                                                   </object>
                                                 </child>
                                               </object>
@@ -5078,11 +5082,13 @@ filter_output([
                                                 <property name="vexpand">True</property>
                                                 <property name="halign">GTK_ALIGN_FILL</property>
                                                 <child>
-                                                  <object class="GtkListBox" id="subtitle_avail_lang">
+                                                  <object class="GtkTreeView" id="subtitle_avail_lang">
                                                     <property name="visible">True</property>
+                                                    <property name="headers-visible">False</property>
                                                     <property name="can_focus">True</property>
                                                     <property name="vexpand">True</property>
                                                     <property name="halign">GTK_ALIGN_FILL</property>
+                                                    <signal name="row-activated" handler="subtitle_avail_lang_activated_cb" swapped="no"/>
                                                   </object>
                                                 </child>
                                               </object>
@@ -5102,8 +5108,9 @@ filter_output([
                                                 <property name="vexpand">True</property>
                                                 <property name="halign">GTK_ALIGN_FILL</property>
                                                 <child>
-                                                  <object class="GtkListBox" id="subtitle_selected_lang">
+                                                  <object class="GtkTreeView" id="subtitle_selected_lang">
                                                     <property name="visible">True</property>
+                                                    <property name="headers-visible">False</property>
                                                     <property name="can_focus">True</property>
                                                     <property name="tooltip_text" translatable="yes">Create a list of languages you would like to select subtitles for.
 Tracks matching these languages will be selected using the chosen Selection Behavior.
@@ -5112,6 +5119,7 @@ The first language in this list is your "preferred" language and will be used
 for determining subtitle selection settings when there is foreign audio.</property>
                                                     <property name="vexpand">True</property>
                                                     <property name="halign">GTK_ALIGN_FILL</property>
+                                                    <signal name="row-activated" handler="subtitle_selected_lang_activated_cb" swapped="no"/>
                                                   </object>
                                                 </child>
                                               </object>
index 433e21bfca2f4e471e57f5230217197c4ec11b09..8a9ed99b0e491d3ef18d45a0d5b836eff2e17765 100644 (file)
@@ -2899,15 +2899,39 @@ ghb_lookup_combo_option(const gchar *name, const GhbValue *gval)
     return result;
 }
 
-void ghb_init_lang_list_box(GtkListBox *list_box)
+void ghb_init_lang_list_model(GtkTreeView *tv)
 {
-    int ii;
+    GtkTreeViewColumn * column;
+    GtkTreeStore      * ts;
+    GtkCellRenderer   * lang_cell;
+
+    // Store contains:
+    // 0 - Language string to display
+    // 1 - Index of language in the libhb language list
+    ts = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_INT);
+    gtk_tree_view_set_model(tv, GTK_TREE_MODEL(ts));
+
+    lang_cell = gtk_cell_renderer_text_new();
+    column = gtk_tree_view_column_new();
+    gtk_tree_view_column_pack_start(column, lang_cell, FALSE);
+    gtk_tree_view_column_add_attribute(column, lang_cell, "markup", 0);
+    gtk_tree_view_append_column(tv, GTK_TREE_VIEW_COLUMN(column));
+}
+
+void ghb_init_lang_list(GtkTreeView *tv, signal_user_data_t *ud)
+{
+    GtkTreeIter    iter;
+    GtkTreeStore * ts;
+    int            ii;
+
+    ghb_init_lang_list_model(tv);
+    ts = GTK_TREE_STORE(gtk_tree_view_get_model(tv));
 
     const iso639_lang_t *iso639;
     for (iso639 = lang_get_next(NULL), ii = 0; iso639 != NULL;
          iso639 = lang_get_next(iso639), ii++)
     {
-        const char *lang;
+        const char * lang;
         if (ii == 0)
         {
             lang = _("Any");
@@ -2921,10 +2945,8 @@ void ghb_init_lang_list_box(GtkListBox *list_box)
         {
             lang = iso639->eng_name;
         }
-        GtkWidget *label = gtk_label_new(lang);
-        g_object_set_data(G_OBJECT(label), "lang_idx", (gpointer)(intptr_t)ii);
-        gtk_widget_show(label);
-        gtk_list_box_insert(list_box, label, -1);
+        gtk_tree_store_append(ts, &iter, NULL);
+        gtk_tree_store_set(ts, &iter, 0, lang, 1, ii, -1);
     }
 }
 
index 481aafbb22f4a77dd6fede03e60f87bd7e8815fd..7ebec5c1a19ff2e9023315009f717f173659d24b 100644 (file)
@@ -169,7 +169,8 @@ const char* ghb_lookup_filter_name(int filter_id, const char *short_name, int pr
 gchar* ghb_get_tmp_dir();
 gint ghb_find_closest_audio_samplerate(gint rate);
 
-void ghb_init_lang_list_box(GtkListBox *list_box);
+void ghb_init_lang_list_model(GtkTreeView *tv);
+void ghb_init_lang_list(GtkTreeView *tv, signal_user_data_t *ud);
 
 void ghb_init_combo_box(GtkComboBox *combo);
 void ghb_audio_encoder_opts_set(GtkComboBox *combo);
index 3cf44689f209660b50b4c3354f77dcedcefdae88..9297c0968e3806c8dc7af3f33ab7960e8aecb40a 100644 (file)
@@ -1329,80 +1329,137 @@ ghb_subtitle_set_pref_lang(GhbValue *settings)
     }
 }
 
-G_MODULE_EXPORT void
-subtitle_add_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+void
+subtitle_add_lang_iter(GtkTreeModel *tm, GtkTreeIter *iter,
+                       signal_user_data_t *ud)
 {
-    GtkListBox *avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
-    GtkListBox *selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
-    GtkListBoxRow *row;
-    GtkWidget *label;
-
-    row = gtk_list_box_get_selected_row(avail);
-    if (row != NULL)
-    {
-        int idx;
-        const iso639_lang_t *lang;
-        GhbValue *glang, *lang_list;
-
-        // Remove from UI available language list box
-        label = gtk_bin_get_child(GTK_BIN(row));
-        g_object_ref(G_OBJECT(label));
-        gtk_widget_destroy(GTK_WIDGET(row));
-        gtk_widget_show(label);
-        // Add to UI selected language list box
-        gtk_list_box_insert(selected, label, -1);
-
-        // Add to preset language list
-        idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-        lang = ghb_iso639_lookup_by_int(idx);
-        glang = ghb_string_value_new(lang->iso639_2);
-        lang_list = ghb_dict_get_value(ud->settings, "SubtitleLanguageList");
-        if (ghb_array_len(lang_list) == 0)
-        {
-            subtitle_update_pref_lang(ud, lang);
-        }
-        ghb_array_append(lang_list, glang);
-        ghb_clear_presets_selection(ud);
+    GtkTreeView         * selected;
+    GtkTreeStore        * selected_ts;
+    GtkTreeIter           pos;
+    GtkTreePath         * tp;
+    char                * lang;
+    int                   index;
+    const iso639_lang_t * iso_lang;
+    GhbValue            * glang, * slang_list;
+    GtkTreeSelection    * tsel;
+
+    selected    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
+    selected_ts = GTK_TREE_STORE(gtk_tree_view_get_model(selected));
+    tsel        = gtk_tree_view_get_selection(selected);
+
+    // Add to UI selected language list box
+    gtk_tree_model_get(tm, iter, 0, &lang, 1, &index, -1);
+    gtk_tree_store_append(selected_ts, &pos, NULL);
+    gtk_tree_store_set(selected_ts, &pos, 0, lang, 1, index, -1);
+    g_free(lang);
+
+    // Select the item added to the selected list and make it
+    // visible in the scrolled window
+    tp = gtk_tree_model_get_path(GTK_TREE_MODEL(selected_ts), &pos);
+    gtk_tree_selection_select_iter(tsel, &pos);
+    gtk_tree_view_scroll_to_cell(selected, tp, NULL, FALSE, 0, 0);
+    gtk_tree_path_free(tp);
+
+    // Remove from UI available language list box
+    gtk_tree_store_remove(GTK_TREE_STORE(tm), iter);
+
+    // Add to preset language list
+    iso_lang = ghb_iso639_lookup_by_int(index);
+    glang = ghb_string_value_new(iso_lang->iso639_2);
+    slang_list = ghb_dict_get_value(ud->settings, "SubtitleLanguageList");
+    if (ghb_array_len(slang_list) == 0)
+    {
+        subtitle_update_pref_lang(ud, iso_lang);
     }
+    ghb_array_append(slang_list, glang);
+    ghb_clear_presets_selection(ud);
 }
 
 G_MODULE_EXPORT void
-subtitle_remove_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+subtitle_avail_lang_activated_cb(GtkTreeView *tv, GtkTreePath *tp,
+                                 GtkTreeViewColumn *column,
+                                 signal_user_data_t *ud)
 {
+    GtkTreeIter    iter;
+    GtkTreeModel * tm = gtk_tree_view_get_model(tv);
 
-    GtkListBox *avail, *selected;
-    GtkListBoxRow *row;
-    GtkWidget *label;
+    if (gtk_tree_model_get_iter(tm, &iter, tp))
+    {
+        subtitle_add_lang_iter(tm, &iter, ud);
+    }
+}
 
-    avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
-    selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
-    row = gtk_list_box_get_selected_row(selected);
-    if (row != NULL)
+G_MODULE_EXPORT void
+subtitle_add_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+    GtkTreeView      * avail;
+    GtkTreeModel     * avail_tm;
+    GtkTreeSelection * tsel;
+    GtkTreeIter        iter;
+
+    avail       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
+    avail_tm    = gtk_tree_view_get_model(avail);
+    tsel        = gtk_tree_view_get_selection(avail);
+    if (gtk_tree_selection_get_selected(tsel, NULL, &iter))
     {
-        gint index;
-        GhbValue *lang_list;
+        subtitle_add_lang_iter(avail_tm, &iter, ud);
+    }
+}
+
+void
+subtitle_remove_lang_iter(GtkTreeModel *tm, GtkTreeIter *iter,
+                          signal_user_data_t *ud)
+{
+    GtkTreeView      * avail;
+    GtkTreeStore     * avail_ts;
+    GtkTreeIter        pos, sibling;
+    char             * lang;
+    int                index;
+    GtkTreePath      * tp  = gtk_tree_model_get_path(tm, iter);
+    int              * ind = gtk_tree_path_get_indices(tp);
+    int                row = ind[0];
+    GhbValue         * slang_list;
+    GtkTreeSelection * tsel;
+
+    gtk_tree_path_free(tp);
+    avail    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
+    avail_ts = GTK_TREE_STORE(gtk_tree_view_get_model(avail));
+    tsel     = gtk_tree_view_get_selection(avail);
 
-        index = gtk_list_box_row_get_index(row);
+    // Add to UI available language list box
+    gtk_tree_model_get(tm, iter, 0, &lang, 1, &index, -1);
+    if (ghb_find_lang_row(GTK_TREE_MODEL(avail_ts), &sibling, index))
+    {
+        gtk_tree_store_insert_before(avail_ts, &pos, NULL, &sibling);
+    }
+    else
+    {
+        gtk_tree_store_append(avail_ts, &pos, NULL);
+    }
+    gtk_tree_store_set(avail_ts, &pos, 0, lang, 1, index, -1);
+    g_free(lang);
 
-        // Remove from UI selected language list box
-        label = gtk_bin_get_child(GTK_BIN(row));
-        g_object_ref(G_OBJECT(label));
-        int idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-        gtk_widget_destroy(GTK_WIDGET(row));
-        gtk_widget_show(label);
-        // Add to UI available language list box
-        gtk_list_box_insert(avail, label, idx);
+    // Select the item added to the available list and make it
+    // visible in the scrolled window
+    tp = gtk_tree_model_get_path(GTK_TREE_MODEL(avail_ts), &pos);
+    gtk_tree_selection_select_iter(tsel, &pos);
+    gtk_tree_view_scroll_to_cell(avail, tp, NULL, FALSE, 0, 0);
+    gtk_tree_path_free(tp);
 
-        // Remove from preset language list
-        lang_list = ghb_dict_get_value(ud->settings, "SubtitleLanguageList");
-        ghb_array_remove(lang_list, index);
+    // Remove from UI selected language list box
+    gtk_tree_store_remove(GTK_TREE_STORE(tm), iter);
 
-        ghb_clear_presets_selection(ud);
+    // Remove from preset language list
+    slang_list = ghb_dict_get_value(ud->settings, "SubtitleLanguageList");
+    ghb_array_remove(slang_list, row);
+    ghb_clear_presets_selection(ud);
 
-        if (ghb_array_len(lang_list) > 0)
+    if (row == 0)
+    {
+        if (ghb_array_len(slang_list) > 0)
         {
             const iso639_lang_t *lang;
-            GhbValue *entry = ghb_array_get(lang_list, 0);
+            GhbValue *entry = ghb_array_get(slang_list, 0);
             lang = ghb_iso639_lookup_by_int(ghb_lookup_lang(entry));
             subtitle_update_pref_lang(ud, lang);
         }
@@ -1413,29 +1470,85 @@ subtitle_remove_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
     }
 }
 
-static void subtitle_def_lang_list_clear_cb(GtkWidget *row, gpointer data)
+G_MODULE_EXPORT void
+subtitle_selected_lang_activated_cb(GtkTreeView *tv, GtkTreePath *tp,
+                                    GtkTreeViewColumn *column,
+                                    signal_user_data_t *ud)
 {
-    GtkListBox *avail = (GtkListBox*)data;
-    GtkWidget *label = gtk_bin_get_child(GTK_BIN(row));
-    g_object_ref(G_OBJECT(label));
-    gtk_widget_destroy(GTK_WIDGET(row));
-    gtk_widget_show(label);
-    int idx = (intptr_t)g_object_get_data(G_OBJECT(label), "lang_idx");
-    gtk_list_box_insert(avail, label, idx);
+    GtkTreeIter    iter;
+    GtkTreeModel * tm = gtk_tree_view_get_model(tv);
+
+    if (gtk_tree_model_get_iter(tm, &iter, tp))
+    {
+        subtitle_remove_lang_iter(tm, &iter, ud);
+    }
+}
+
+G_MODULE_EXPORT void
+subtitle_remove_lang_clicked_cb(GtkWidget *widget, signal_user_data_t *ud)
+{
+    GtkTreeView      * selected;
+    GtkTreeModel     * selected_tm;
+    GtkTreeSelection * tsel;
+    GtkTreeIter        iter;
+
+    selected    = GTK_TREE_VIEW(GHB_WIDGET(ud->builder,
+                                           "subtitle_selected_lang"));
+    selected_tm = gtk_tree_view_get_model(selected);
+    tsel        = gtk_tree_view_get_selection(selected);
+    if (gtk_tree_selection_get_selected(tsel, NULL, &iter))
+    {
+        subtitle_remove_lang_iter(selected_tm, &iter, ud);
+    }
 }
 
 static void subtitle_def_selected_lang_list_clear(signal_user_data_t *ud)
 {
-    GtkListBox *avail, *selected;
-    avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
-    selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
-    gtk_container_foreach(GTK_CONTAINER(selected),
-                          subtitle_def_lang_list_clear_cb, (gpointer)avail);
+    GtkTreeView  * tv;
+    GtkTreeModel * selected_tm;
+    GtkTreeStore * avail_ts;
+    GtkTreeIter    iter;
+
+    tv          = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
+    avail_ts    = GTK_TREE_STORE(gtk_tree_view_get_model(tv));
+    tv          = GTK_TREE_VIEW(GHB_WIDGET(ud->builder,
+                                           "subtitle_selected_lang"));
+    selected_tm = gtk_tree_view_get_model(tv);
+    if (gtk_tree_model_get_iter_first(selected_tm, &iter))
+    {
+        do
+        {
+            char        * lang;
+            gint          index;
+            GtkTreeIter   pos, sibling;
+
+            gtk_tree_model_get(selected_tm, &iter, 0, &lang, 1, &index, -1);
+            if (ghb_find_lang_row(GTK_TREE_MODEL(avail_ts), &sibling, index))
+            {
+                gtk_tree_store_insert_before(avail_ts, &pos, NULL, &sibling);
+            }
+            else
+            {
+                gtk_tree_store_append(avail_ts, &pos, NULL);
+            }
+            gtk_tree_store_set(avail_ts, &pos, 0, lang, 1, index, -1);
+        } while (gtk_tree_model_iter_next(selected_tm, &iter));
+    }
+    gtk_tree_store_clear(GTK_TREE_STORE(selected_tm));
 }
 
 static void subtitle_def_lang_list_init(signal_user_data_t *ud)
 {
-    GhbValue *lang_list;
+    GhbValue     * lang_list;
+    GtkTreeView  * tv;
+    GtkTreeModel * avail;
+    GtkTreeStore * selected;
+    int            ii, count;
+
+    tv       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
+    avail    = gtk_tree_view_get_model(tv);
+    tv       = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
+    selected = GTK_TREE_STORE(gtk_tree_view_get_model(tv));
 
     // Clear selected languages.
     subtitle_def_selected_lang_list_clear(ud);
@@ -1447,31 +1560,30 @@ static void subtitle_def_lang_list_init(signal_user_data_t *ud)
         ghb_dict_set(ud->settings, "SubtitleLanguageList", lang_list);
     }
 
-    int ii, count;
     count = ghb_array_len(lang_list);
     for (ii = 0; ii < count; )
     {
-        GhbValue *lang_val = ghb_array_get(lang_list, ii);
-        int idx = ghb_lookup_lang(lang_val);
+        GhbValue    * lang_val = ghb_array_get(lang_list, ii);
+        int           idx      = ghb_lookup_lang(lang_val);
+        GtkTreeIter   iter;
+
         if (ii == 0)
         {
             const iso639_lang_t *lang;
             lang = ghb_iso639_lookup_by_int(idx);
             subtitle_update_pref_lang(ud, lang);
         }
-
-        GtkListBox *avail, *selected;
-        GtkListBoxRow *row;
-        avail = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
-        selected = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
-        row = ghb_find_lang_row(avail, idx);
-        if (row)
+        if (ghb_find_lang_row(avail, &iter, idx))
         {
-            GtkWidget *label = gtk_bin_get_child(GTK_BIN(row));
-            g_object_ref(G_OBJECT(label));
-            gtk_widget_destroy(GTK_WIDGET(row));
-            gtk_widget_show(label);
-            gtk_list_box_insert(selected, label, -1);
+            gchar       * lang;
+            gint          index;
+            GtkTreeIter   pos;
+
+            gtk_tree_model_get(avail, &iter, 0, &lang, 1, &index, -1);
+            gtk_tree_store_append(selected, &pos, NULL);
+            gtk_tree_store_set(selected, &pos, 0, lang, 1, index, -1);
+            g_free(lang);
+            gtk_tree_store_remove(GTK_TREE_STORE(avail), &iter);
             ii++;
         }
         else
@@ -1495,10 +1607,12 @@ void ghb_subtitle_defaults_to_ui(signal_user_data_t *ud)
 
 void ghb_init_subtitle_defaults_ui(signal_user_data_t *ud)
 {
-    GtkListBox *list_box;
+    GtkTreeView * tv;
 
-    list_box = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
-    ghb_init_lang_list_box(list_box);
+    tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_avail_lang"));
+    ghb_init_lang_list(tv, ud);
+    tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "subtitle_selected_lang"));
+    ghb_init_lang_list_model(tv);
 }
 
 G_MODULE_EXPORT void