[gtranslator: 2/5] New lang button widget



commit e8a0e79989ce6fe7284ba609b3d8668d6c473991
Author: Daniel GarcĂ­a Moreno <danigm wadobo com>
Date:   Thu Oct 25 14:59:29 2018 +0200

    New lang button widget
    
    See #16

 src/gtr-lang-button.c         | 209 ++++++++++++++++++++++++++++++++++++++++++
 src/gtr-lang-button.h         |  35 +++++++
 src/gtr-lang-button.ui        |  74 +++++++++++++++
 src/gtr-languages-fetcher.c   |  96 +++++++------------
 src/gtr-languages-fetcher.ui  |  10 +-
 src/gtranslator.gresource.xml |   1 +
 src/meson.build               |   3 +-
 7 files changed, 354 insertions(+), 74 deletions(-)
---
diff --git a/src/gtr-lang-button.c b/src/gtr-lang-button.c
new file mode 100644
index 00000000..918c3441
--- /dev/null
+++ b/src/gtr-lang-button.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2018  Daniel Garcia Moreno <danigm gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gtr-language.h"
+#include "gtr-lang-button.h"
+
+typedef struct
+{
+  GtkWidget *lang;
+  GtkWidget *lang_list;
+  GtkWidget *popup;
+  gchar *lang_name;
+
+} GtrLangButtonPrivate;
+
+struct _GtrLangButton
+{
+  GtkMenuButton parent_instance;
+};
+
+enum
+{
+  CHANGED,
+  LAST_SIGNAL
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GtrLangButton, gtr_lang_button, GTK_TYPE_MENU_BUTTON)
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static gint
+compare_languages_name (gconstpointer a,
+                        gconstpointer b)
+{
+  GtrLanguage *lang1, *lang2;
+  const gchar *name1, *name2;
+
+  lang1 = (GtrLanguage *) a;
+  lang2 = (GtrLanguage *) b;
+
+  name1 = gtr_language_get_name (lang1);
+  name2 = gtr_language_get_name (lang2);
+
+  return g_utf8_collate (name1, name2);
+}
+
+static void
+change_language (GtkListBox    *box,
+                 GtkListBoxRow *row,
+                 GtrLangButton *self)
+{
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (self);
+  GtkWidget *label = gtk_bin_get_child (GTK_BIN (row));
+  gtr_lang_button_set_lang (self, gtk_label_get_text (GTK_LABEL (label)));
+
+  gtk_popover_popdown (GTK_POPOVER (priv->popup));
+}
+
+static void
+filter_language (GtkEditable   *entry,
+                 GtrLangButton *self)
+{
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (self);
+  const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry));
+  gchar *uptext = g_ascii_strup (text, -1);
+  const GSList *languages, *l;
+  GList *children;
+
+  languages = gtr_language_get_languages ();
+  languages = g_slist_sort ((GSList*)languages, compare_languages_name);
+
+  children = gtk_container_get_children (GTK_CONTAINER (priv->lang_list));
+  while (children)
+    {
+      GtkWidget *w = GTK_WIDGET (children->data);
+      gtk_container_remove (GTK_CONTAINER (priv->lang_list), w);
+      children = g_list_next (children);
+    }
+
+  for (l = languages; l != NULL; l = g_slist_next (l))
+    {
+      GtrLanguage *lang = (GtrLanguage *)l->data;
+      const gchar *langname = gtr_language_get_name (lang);
+      GtkWidget *child;
+      gchar *uplang = g_ascii_strup (langname, -1);
+
+      if (g_strrstr (uplang, uptext) == NULL) {
+        g_free (uplang);
+        continue;
+      }
+      g_free (uplang);
+
+      child = gtk_label_new (langname);
+      gtk_label_set_xalign (GTK_LABEL (child), 0.0);
+      gtk_container_add (GTK_CONTAINER (priv->lang_list), child);
+    }
+  gtk_widget_show_all (priv->lang_list);
+
+  g_free (uptext);
+}
+
+static void
+gtr_lang_button_finalize (GObject *object)
+{
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (GTR_LANG_BUTTON (object));
+
+  g_clear_pointer (&priv->lang_name, g_free);
+
+  G_OBJECT_CLASS (gtr_lang_button_parent_class)->finalize (object);
+}
+
+static void
+gtr_lang_button_class_init (GtrLangButtonClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->finalize = gtr_lang_button_finalize;
+
+  signals[CHANGED] =
+    g_signal_newv ("changed",
+                   G_OBJECT_CLASS_TYPE (object_class),
+                   G_SIGNAL_RUN_LAST,
+                   NULL, NULL, NULL, NULL,
+                   G_TYPE_NONE, 0, NULL);
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gnome/translator/gtr-lang-button.ui");
+
+  gtk_widget_class_bind_template_child_private (widget_class, GtrLangButton, lang);
+  gtk_widget_class_bind_template_child_private (widget_class, GtrLangButton, lang_list);
+  gtk_widget_class_bind_template_child_private (widget_class, GtrLangButton, popup);
+}
+
+static void
+gtr_lang_button_init (GtrLangButton *self)
+{
+  const GSList *languages, *l;
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (self);
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  languages = gtr_language_get_languages ();
+  languages = g_slist_sort ((GSList*)languages, compare_languages_name);
+
+  for (l = languages; l != NULL; l = g_slist_next (l))
+    {
+      GtrLanguage *lang = (GtrLanguage *)l->data;
+      GtkWidget *child = gtk_label_new (gtr_language_get_name (lang));
+      gtk_label_set_xalign (GTK_LABEL (child), 0.0);
+      gtk_container_add (GTK_CONTAINER (priv->lang_list), child);
+    }
+
+  gtk_widget_show_all (priv->lang_list);
+  priv->lang_name = NULL;
+
+  g_signal_connect (priv->lang_list,
+                    "row-activated",
+                    G_CALLBACK (change_language),
+                    self);
+
+  g_signal_connect (priv->lang,
+                    "changed",
+                    G_CALLBACK (filter_language),
+                    self);
+}
+
+GtrLangButton*
+gtr_lang_button_new () {
+  GtrLangButton *self = g_object_new (GTR_TYPE_LANG_BUTTON, NULL);
+  return self;
+}
+
+const gchar *
+gtr_lang_button_get_lang (GtrLangButton *self)
+{
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (self);
+  return priv->lang_name;
+}
+
+void
+gtr_lang_button_set_lang (GtrLangButton *self,
+                          const gchar   *name)
+{
+  GtrLangButtonPrivate *priv = gtr_lang_button_get_instance_private (self);
+  g_clear_pointer (&priv->lang_name, g_free);
+  priv->lang_name = g_strdup (name);
+  gtk_button_set_label (GTK_BUTTON (self), name);
+  g_signal_emit (self, signals[CHANGED], 0, NULL);
+}
+
diff --git a/src/gtr-lang-button.h b/src/gtr-lang-button.h
new file mode 100644
index 00000000..cacd69fe
--- /dev/null
+++ b/src/gtr-lang-button.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018  Daniel Garcia Moreno <danigm gnome org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GTR_TYPE_LANG_BUTTON (gtr_lang_button_get_type())
+
+G_DECLARE_FINAL_TYPE (GtrLangButton, gtr_lang_button, GTR, LANG_BUTTON, GtkMenuButton)
+
+GtrLangButton*  gtr_lang_button_new       ();
+const gchar *   gtr_lang_button_get_lang  (GtrLangButton *self);
+void            gtr_lang_button_set_lang  (GtrLangButton *self,
+                                           const gchar   *name);
+
+G_END_DECLS
+
diff --git a/src/gtr-lang-button.ui b/src/gtr-lang-button.ui
new file mode 100644
index 00000000..fe5c693b
--- /dev/null
+++ b/src/gtr-lang-button.ui
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+  <requires lib="gtk+" version="3.12"/>
+  <object class="GtkPopover" id="popup">
+    <property name="can_focus">False</property>
+    <property name="position">right</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="margin_left">6</property>
+        <property name="margin_right">6</property>
+        <property name="margin_top">6</property>
+        <property name="margin_bottom">6</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">4</property>
+        <child>
+          <object class="GtkEntry" id="lang">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow">
+            <property name="height_request">200</property>
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="vexpand">True</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkViewport">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkListBox" id="lang_list">
+                    <property name="name">lang_list</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="vexpand">True</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <template class="GtrLangButton" parent="GtkMenuButton">
+    <property name="label" translatable="yes">Choose Language</property>
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="receives_default">False</property>
+    <property name="popover">popup</property>
+    <child>
+      <object class="GtkLabel">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label" translatable="yes">Choose Language</property>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/gtr-languages-fetcher.c b/src/gtr-languages-fetcher.c
index 9f49435b..4068bce8 100644
--- a/src/gtr-languages-fetcher.c
+++ b/src/gtr-languages-fetcher.c
@@ -22,6 +22,7 @@
 #include "gtr-languages-fetcher.h"
 #include "gtr-language.h"
 #include "gtr-utils.h"
+#include "gtr-lang-button.h"
 #include <string.h>
 
 typedef struct
@@ -34,7 +35,6 @@ typedef struct
   GtkWidget *plural_forms;
   GtkWidget *advanced;
 
-  GtkListStore *language_store;
   GtkListStore *code_store;
 } GtrLanguagesFetcherPrivate;
 
@@ -78,22 +78,6 @@ gtr_languages_fetcher_class_init (GtrLanguagesFetcherClass *klass)
                   0);
 }
 
-static gint
-compare_languages_name (gconstpointer a,
-                        gconstpointer b)
-{
-  GtrLanguage *lang1, *lang2;
-  const gchar *name1, *name2;
-
-  lang1 = (GtrLanguage *) a;
-  lang2 = (GtrLanguage *) b;
-
-  name1 = gtr_language_get_name (lang1);
-  name2 = gtr_language_get_name (lang2);
-
-  return g_utf8_collate (name1, name2);
-}
-
 static gint
 compare_languages_code (gconstpointer a,
                         gconstpointer b)
@@ -120,20 +104,6 @@ append_from_languages (GtrLanguagesFetcher *fetcher)
   plurals = g_hash_table_new (g_str_hash, g_int_equal);
 
   languages = gtr_language_get_languages ();
-  languages = g_slist_sort ((GSList *)languages, compare_languages_name);
-
-  for (l = languages; l != NULL; l = g_slist_next (l))
-    {
-      GtrLanguage *lang = (GtrLanguage *)l->data;
-      GtkTreeIter iter1;
-
-      gtk_list_store_append (priv->language_store, &iter1);
-      gtk_list_store_set (priv->language_store, &iter1,
-                          0, gtr_language_get_name (lang),
-                          1, lang,
-                           -1);
-    }
-
   languages = g_slist_sort ((GSList *)languages, compare_languages_code);
 
   for (l = languages; l != NULL; l = g_slist_next (l))
@@ -211,7 +181,7 @@ fill_from_language_code_entry (GtrLanguagesFetcher *fetcher,
 
   fill_encoding_and_charset (fetcher);
 
-  entry_text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->language))));
+  entry_text = gtr_lang_button_get_lang (GTR_LANG_BUTTON (priv->language));
 
   if (*entry_text == '\0')
     {
@@ -220,7 +190,7 @@ fill_from_language_code_entry (GtrLanguagesFetcher *fetcher,
       name = gtr_language_get_name (lang);
 
       if (name != NULL && *name != '\0')
-        gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->language))), name);
+        gtr_lang_button_set_lang (GTR_LANG_BUTTON (priv->language), name);
     }
 
   entry_text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->plural_forms))));
@@ -240,18 +210,15 @@ typedef void (* fill_method) (GtrLanguagesFetcher *fetcher, GtrLanguage *lang);
 
 static void
 fill_boxes (GtrLanguagesFetcher *fetcher,
-            GtkEntry            *entry,
+            const gchar         *text,
             GtkTreeModel        *store,
             fill_method          fill)
 {
-  const gchar *text;
   gchar *entry_row;
   GtkTreeIter iter;
   GtrLanguage *lang;
   gboolean found = FALSE;
 
-  text = gtk_entry_get_text (entry);
-
   if (text == NULL || *text == '\0' ||
       !gtk_tree_model_get_iter_first (store, &iter))
     return;
@@ -284,30 +251,35 @@ fill_boxes (GtrLanguagesFetcher *fetcher,
 }
 
 static void
-on_language_activate (GtkEntry         *entry,
+on_language_activate (GtrLangButton       *btn,
                       GtrLanguagesFetcher *fetcher)
 {
   GtrLanguagesFetcherPrivate *priv = gtr_languages_fetcher_get_instance_private (fetcher);
-  fill_boxes (fetcher, entry, GTK_TREE_MODEL (priv->language_store),
-              fill_from_language_entry);
-}
-
-static gboolean
-on_language_focus_out_event (GtkEntry         *entry,
-                             GdkEvent         *event,
-                             GtrLanguagesFetcher *fetcher)
-{
-  on_language_activate (entry, fetcher);
+  const gchar *text = gtr_lang_button_get_lang (GTR_LANG_BUTTON (priv->language));
+  GtrLanguage *lang;
+  const GSList *l;
+  const GSList *languages = gtr_language_get_languages ();
 
-  return FALSE;
+  for (l = languages; l != NULL; l = g_slist_next (l))
+    {
+      lang = (GtrLanguage*)l->data;
+      const gchar *langname = gtr_language_get_name (lang);
+      if (text != NULL && strcmp (langname, text) == 0)
+        {
+          fill_from_language_entry (fetcher, lang);
+          break;
+        }
+    }
 }
 
 static void
-on_language_code_activate (GtkEntry         *entry,
+on_language_code_activate (GtkEntry            *entry,
                            GtrLanguagesFetcher *fetcher)
 {
   GtrLanguagesFetcherPrivate *priv = gtr_languages_fetcher_get_instance_private (fetcher);
-  fill_boxes (fetcher, entry, GTK_TREE_MODEL (priv->code_store),
+  const gchar *text = gtk_entry_get_text (entry);
+
+  fill_boxes (fetcher, text, GTK_TREE_MODEL (priv->code_store),
               fill_from_language_code_entry);
 }
 
@@ -346,9 +318,7 @@ on_lang_changed (GtkWidget           *widget,
                  GtrLanguagesFetcher *fetcher)
 {
   GtrLanguagesFetcherPrivate *priv = gtr_languages_fetcher_get_instance_private (fetcher);
-  GtkWidget *entry = gtk_bin_get_child (GTK_BIN (priv->language));
-
-  on_language_activate (GTK_ENTRY (entry), fetcher);
+  on_language_activate (GTR_LANG_BUTTON (priv->language), fetcher);
   g_signal_emit (fetcher, signals[CHANGED], 0, NULL);
 }
 
@@ -359,7 +329,6 @@ gtr_languages_fetcher_init (GtrLanguagesFetcher *fetcher)
   GtkBuilder *builder;
   gchar *root_objects[] = {
     "main_box",
-    "language_store",
     "code_store",
     NULL
   };
@@ -368,9 +337,12 @@ gtr_languages_fetcher_init (GtrLanguagesFetcher *fetcher)
   gtk_orientable_set_orientation (GTK_ORIENTABLE (fetcher),
                                   GTK_ORIENTATION_VERTICAL);
 
+  g_type_ensure (gtr_lang_button_get_type ());
+
   builder = gtk_builder_new ();
   gtk_builder_add_objects_from_resource (builder, "/org/gnome/translator/gtr-languages-fetcher.ui",
                                          root_objects, NULL);
+
   content = GTK_WIDGET (gtk_builder_get_object (builder, "main_box"));
   g_object_ref (content);
   priv->language = GTK_WIDGET (gtk_builder_get_object (builder, "language"));
@@ -379,8 +351,8 @@ gtr_languages_fetcher_init (GtrLanguagesFetcher *fetcher)
   priv->encoding = GTK_WIDGET (gtk_builder_get_object (builder, "encoding"));
   priv->plural_forms = GTK_WIDGET (gtk_builder_get_object (builder, "plural_forms"));
   priv->advanced = GTK_WIDGET (gtk_builder_get_object (builder, "advanced_check"));
-  priv->language_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "language_store"));
   priv->code_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "code_store"));
+
   g_object_unref (builder);
 
   gtk_box_pack_start (GTK_BOX (fetcher), content, FALSE, FALSE, 0);
@@ -388,14 +360,10 @@ gtr_languages_fetcher_init (GtrLanguagesFetcher *fetcher)
   /* add items to comboboxes */
   append_from_languages (fetcher);
 
-  g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->language)),
-                    "activate",
+  g_signal_connect (G_OBJECT (priv->language),
+                    "clicked",
                     G_CALLBACK (on_language_activate),
                     fetcher);
-  g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->language)),
-                    "focus-out-event",
-                    G_CALLBACK (on_language_focus_out_event),
-                    fetcher);
   g_signal_connect (gtk_bin_get_child (GTK_BIN (priv->language_code)),
                     "activate",
                     G_CALLBACK (on_language_code_activate),
@@ -439,7 +407,7 @@ gtr_languages_fetcher_get_language_name (GtrLanguagesFetcher *fetcher)
   GtrLanguagesFetcherPrivate *priv = gtr_languages_fetcher_get_instance_private (fetcher);
   g_return_val_if_fail (GTR_IS_LANGUAGES_FETCHER (fetcher), NULL);
 
-  return gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->language))));
+  return gtr_lang_button_get_lang (GTR_LANG_BUTTON (priv->language));
 }
 
 void
@@ -450,7 +418,7 @@ gtr_languages_fetcher_set_language_name (GtrLanguagesFetcher *fetcher,
   g_return_if_fail (GTR_IS_LANGUAGES_FETCHER (fetcher));
   g_return_if_fail (name != NULL);
 
-  gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->language))), name);
+  gtr_lang_button_set_lang (GTR_LANG_BUTTON (priv->language), name);
 }
 
 const gchar *
diff --git a/src/gtr-languages-fetcher.ui b/src/gtr-languages-fetcher.ui
index 80c9064c..f3d074cb 100644
--- a/src/gtr-languages-fetcher.ui
+++ b/src/gtr-languages-fetcher.ui
@@ -185,18 +185,10 @@
               </packing>
             </child>
             <child>
-              <object class="GtkComboBox" id="language">
+              <object class="GtrLangButton" id="language">
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
                 <property name="hexpand">True</property>
-                <property name="model">language_store</property>
-                <property name="has_entry">True</property>
-                <property name="entry_text_column">0</property>
-                <child internal-child="entry">
-                  <object class="GtkEntry">
-                    <property name="can_focus">True</property>
-                  </object>
-                </child>
               </object>
               <packing>
                 <property name="left_attach">1</property>
diff --git a/src/gtranslator.gresource.xml b/src/gtranslator.gresource.xml
index bf790226..b67c3071 100644
--- a/src/gtranslator.gresource.xml
+++ b/src/gtranslator.gresource.xml
@@ -17,6 +17,7 @@
     <file preprocess="xml-stripblanks">gtr-tab.ui</file>
     <file preprocess="xml-stripblanks">gtr-window.ui</file>
     <file preprocess="xml-stripblanks">gtr-projects.ui</file>
+    <file preprocess="xml-stripblanks">gtr-lang-button.ui</file>
     <file preprocess="xml-stripblanks">help-overlay.ui</file>
   </gresource>
 </gresources>
diff --git a/src/meson.build b/src/meson.build
index 88bff489..7274aa66 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -62,6 +62,7 @@ sources = files(
   'gtr-utils.c',
   'gtr-view.c',
   'gtr-projects.c',
+  'gtr-lang-button.c',
   'gtr-progress.c',
   'gtr-window.c',
 )
@@ -146,4 +147,4 @@ executable(
   dependencies: gtr_deps,
   objects: libgtranslator.extract_all_objects(),
   install: true,
-)
+)
\ No newline at end of file


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]