[recipes] Add a search/filter list for adding ingredients



commit 4c743dcd918165c6469ce6d8d994e7bba0ceca0e
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Dec 22 21:42:02 2016 -0500

    Add a search/filter list for adding ingredients
    
    This works similarly to our main search filtering, with
    some small differences.

 src/gr-edit-page.c  |  147 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/gr-edit-page.ui |  110 +++++++++++++++++++++++++++++---------
 2 files changed, 226 insertions(+), 31 deletions(-)
---
diff --git a/src/gr-edit-page.c b/src/gr-edit-page.c
index 65133a3..a02b085 100644
--- a/src/gr-edit-page.c
+++ b/src/gr-edit-page.c
@@ -34,6 +34,8 @@
 #include "gr-season.h"
 #include "gr-images.h"
 #include "gr-image-viewer.h"
+#include "gr-ingredient-row.h"
+#include "gr-ingredient.h"
 
 #ifdef GDK_WINDOWING_X11
 #include <gdk/gdkx.h>
@@ -81,12 +83,19 @@ struct _GrEditPage
         GtkWidget *author_label;
         GtkWidget *ingredients_box;
 
+        GtkWidget *ing_list;
+        GtkWidget *ing_search_button;
+        GtkWidget *ing_search_button_label;
+        GtkWidget *ing_search_revealer;
+
         GtkSizeGroup *group;
 
         guint account_response_signal_id;
 
         GList *segments;
         GtkWidget *active_row;
+
+        char *ing_term;
 };
 
 G_DEFINE_TYPE (GrEditPage, gr_edit_page, GTK_TYPE_BOX)
@@ -144,6 +153,8 @@ edit_page_finalize (GObject *object)
         g_clear_object (&self->group);
         g_list_free (self->segments);
 
+        g_free (self->ing_term);
+
         G_OBJECT_CLASS (gr_edit_page_parent_class)->finalize (object);
 }
 
@@ -203,6 +214,9 @@ ingredient_changed (GrEditPage *page)
         gtk_widget_set_sensitive (page->new_ingredient_add_button, strlen (text) > 0);
 }
 
+static void hide_ingredients_search_list (GrEditPage *self,
+                                          gboolean    animate);
+
 static void
 add_ingredient (GtkButton *button, GrEditPage *page)
 {
@@ -213,6 +227,8 @@ add_ingredient (GtkButton *button, GrEditPage *page)
         gtk_popover_set_relative_to (GTK_POPOVER (page->ingredient_popover), GTK_WIDGET (button));
         gtk_button_set_label (GTK_BUTTON (page->new_ingredient_add_button), _("Add"));
         ingredient_changed (page);
+
+        hide_ingredients_search_list (page, FALSE);
         gtk_popover_popup (GTK_POPOVER (page->ingredient_popover));
 }
 
@@ -244,12 +260,14 @@ edit_ingredients_row (GtkListBoxRow *row,
         ingredient = (const char *)g_object_get_data (G_OBJECT (row), "ingredient");
 
         gtk_entry_set_text (GTK_ENTRY (page->new_ingredient_name), ingredient);
+        gtk_label_set_label (GTK_LABEL (page->ing_search_button_label), ingredient);
         gtk_entry_set_text (GTK_ENTRY (page->new_ingredient_amount), amount);
         gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (page->new_ingredient_unit))), unit);
 
         gtk_popover_set_relative_to (GTK_POPOVER (page->ingredient_popover), GTK_WIDGET (row));
         gtk_button_set_label (GTK_BUTTON (page->new_ingredient_add_button), _("Apply"));
         ingredient_changed (page);
+        hide_ingredients_search_list (page, FALSE);
         gtk_popover_popup (GTK_POPOVER (page->ingredient_popover));
 }
 
@@ -399,7 +417,7 @@ static void
 add_ingredient2 (GtkButton *button, GrEditPage *page)
 {
         const char *ingredient;
-        double amount;
+        const char *amount;
         const char *unit;
         g_autofree char *s = NULL;
         GtkWidget *list;
@@ -418,10 +436,9 @@ add_ingredient2 (GtkButton *button, GrEditPage *page)
         }
 
         ingredient = gtk_entry_get_text (GTK_ENTRY (page->new_ingredient_name));
-        amount = gtk_spin_button_get_value (GTK_SPIN_BUTTON (page->new_ingredient_amount));
+        amount = gtk_entry_get_text (GTK_ENTRY (page->new_ingredient_amount));
         unit = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (page->new_ingredient_unit))));
-        s = g_strdup_printf ("%g", amount);
-        update_ingredient_row (row, s, unit, ingredient);
+        update_ingredient_row (row, amount, unit, ingredient);
 }
 
 static char *
@@ -475,6 +492,118 @@ all_headers (GtkListBoxRow *row,
 }
 
 static void
+show_ingredients_search_list (GrEditPage *self)
+{
+        gtk_widget_hide (self->ing_search_button);
+        gtk_widget_show (self->ing_search_revealer);
+        gtk_revealer_set_reveal_child (GTK_REVEALER (self->ing_search_revealer), TRUE);
+}
+
+static void
+hide_ingredients_search_list (GrEditPage *self,
+                              gboolean    animate)
+{
+        gtk_widget_show (self->ing_search_button);
+        if (!animate)
+                gtk_revealer_set_transition_type (GTK_REVEALER (self->ing_search_revealer),
+                                                  GTK_REVEALER_TRANSITION_TYPE_NONE);
+        gtk_revealer_set_reveal_child (GTK_REVEALER (self->ing_search_revealer), FALSE);
+        if (!animate)
+                gtk_revealer_set_transition_type (GTK_REVEALER (self->ing_search_revealer),
+                                                  GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
+}
+
+static void
+ing_search_button_clicked (GtkButton  *button,
+                           GrEditPage *self)
+{
+        show_ingredients_search_list (self);
+}
+
+static void
+ing_row_activated (GtkListBox    *list,
+                   GtkListBoxRow *row,
+                   GrEditPage *self)
+{
+        const char *ingredient;
+
+        ingredient = gr_ingredient_row_get_ingredient (GR_INGREDIENT_ROW (row));
+        gtk_entry_set_text (GTK_ENTRY (self->new_ingredient_name), ingredient);
+        gtk_label_set_label (GTK_LABEL (self->ing_search_button_label), ingredient);
+        hide_ingredients_search_list (self, TRUE);
+}
+
+static gboolean
+ing_filter_func (GtkListBoxRow *row,
+                 gpointer       data)
+{
+        GrEditPage *self = data;
+        const char *cf;
+
+        if (!GR_IS_INGREDIENT_ROW (row))
+                return TRUE;
+
+        if (!self->ing_term)
+                return TRUE;
+
+        cf = gr_ingredient_row_get_filter_term (GR_INGREDIENT_ROW (row));
+
+        return g_str_has_prefix (cf, self->ing_term);
+}
+
+static void
+ing_filter_changed (GrEditPage *self)
+{
+        const char *term;
+
+        term = gtk_entry_get_text (GTK_ENTRY (self->new_ingredient_name));
+        g_free (self->ing_term);
+        self->ing_term = g_utf8_casefold (term, -1);
+        gtk_list_box_invalidate_filter (GTK_LIST_BOX (self->ing_list));
+}
+
+static void
+ing_filter_stop (GrEditPage *self)
+{
+        gtk_entry_set_text (GTK_ENTRY (self->new_ingredient_name), "");
+}
+
+static void
+ing_filter_activated (GrEditPage *self)
+{
+        const char *ingredient;
+
+        ingredient = gtk_entry_get_text (GTK_ENTRY (self->new_ingredient_name));
+        gtk_label_set_label (GTK_LABEL (self->ing_search_button_label), ingredient);
+        hide_ingredients_search_list (self, TRUE);
+}
+
+static void
+populate_ingredients_list (GrEditPage *self)
+{
+        int i;
+        const char **ingredients;
+        GtkWidget *row;
+
+        ingredients = gr_ingredient_get_names (NULL);
+        for (i = 0; ingredients[i]; i++) {
+                row = GTK_WIDGET (gr_ingredient_row_new (ingredients[i]));
+                gtk_widget_show (row);
+                gtk_container_add (GTK_CONTAINER (self->ing_list), row);
+        }
+
+        gtk_list_box_set_header_func (GTK_LIST_BOX (self->ing_list),
+                                      all_headers, self, NULL);
+
+        gtk_list_box_set_filter_func (GTK_LIST_BOX (self->ing_list),
+                                      ing_filter_func, self, NULL);
+
+        g_signal_connect (self->ing_list, "row-activated",
+                          G_CALLBACK (ing_row_activated), self);
+}
+
+
+static void
 gr_edit_page_init (GrEditPage *page)
 {
         gtk_widget_set_has_window (GTK_WIDGET (page), FALSE);
@@ -485,6 +614,7 @@ gr_edit_page_init (GrEditPage *page)
         populate_cuisine_combo (page);
         populate_category_combo (page);
         populate_season_combo (page);
+        populate_ingredients_list (page);
 }
 
 static void
@@ -527,6 +657,10 @@ gr_edit_page_class_init (GrEditPageClass *klass)
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, new_ingredient_amount);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, new_ingredient_unit);
         gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, 
new_ingredient_add_button);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ing_list);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ing_search_button);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ing_search_button_label);
+        gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GrEditPage, ing_search_revealer);
 
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), dismiss_error);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), add_image);
@@ -537,6 +671,11 @@ gr_edit_page_class_init (GrEditPageClass *klass)
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), add_ingredient2);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), remove_ingredient);
         gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), ingredient_changed);
+
+        gtk_widget_class_bind_template_callback (widget_class, ing_filter_changed);
+        gtk_widget_class_bind_template_callback (widget_class, ing_filter_stop);
+        gtk_widget_class_bind_template_callback (widget_class, ing_filter_activated);
+        gtk_widget_class_bind_template_callback (widget_class, ing_search_button_clicked);
 }
 
 GtkWidget *
diff --git a/src/gr-edit-page.ui b/src/gr-edit-page.ui
index afea66a..a14be57 100644
--- a/src/gr-edit-page.ui
+++ b/src/gr-edit-page.ui
@@ -622,6 +622,7 @@
   </template>
   <object class="GtkPopover" id="ingredient_popover">
     <property name="position">top</property>
+    <property name="constrain-to">none</property>
     <child>
       <object class="GtkBox">
         <property name="visible">1</property>
@@ -637,42 +638,104 @@
           </object>
         </child>
         <child>
-          <object class="GtkEntry" id="new_ingredient_name">
+          <object class="GtkButton" id="ing_search_button">
             <property name="visible">1</property>
-            <signal name="notify::text" handler="ingredient_changed" swapped="yes"/>
-          </object>
-        </child>
-        <child>
-          <object class="GtkLabel">
-            <property name="visible">1</property>
-            <property name="label" translatable="yes">Amount</property>
-            <property name="xalign">0</property>
-            <style> <class name="dim-label"/> </style>
+            <signal name="clicked" handler="ing_search_button_clicked"/>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">1</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkLabel" id="ing_search_button_label">
+                    <property name="visible">1</property>
+                    <property name="xalign">0</property>
+                    <property name="ellipsize">end</property>
+                    <property name="max-width-chars">25</property>
+                    <property name="label" translatable="yes">Ingredient</property>
+                  </object>
+                  <packing>
+                    <property name="expand">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">1</property>
+                    <property name="icon-name">pan-down-symbolic</property>
+                    <property name="icon-size">1</property>
+                  </object>
+                </child>
+              </object>
+            </child>
           </object>
         </child>
         <child>
-          <object class="GtkSpinButton" id="new_ingredient_amount">
-            <property name="adjustment">amount_adjustment</property>
+          <object class="GtkRevealer" id="ing_search_revealer">
             <property name="visible">1</property>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">1</property>
+                <property name="orientation">vertical</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkSearchEntry" id="new_ingredient_name">
+                    <property name="visible">1</property>
+                    <property name="placeholder-text" translatable="yes">Search…</property>
+                    <signal name="search-changed" handler="ing_filter_changed" swapped="yes"/>
+                    <signal name="stop-search" handler="ing_filter_stop" swapped="yes"/>
+                    <signal name="activate" handler="ing_filter_activated" swapped="yes"/>
+                    <signal name="notify::text" handler="ingredient_changed" swapped="yes"/>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow">
+                    <property name="visible">1</property>
+                    <property name="shadow-type">in</property>
+                    <property name="hscrollbar-policy">never</property>
+                    <property name="propagate-natural-height">1</property>
+                    <property name="max-content-height">220</property>
+                    <property name="height-request">220</property>
+                    <child>
+                      <object class="GtkListBox" id="ing_list">
+                        <property name="visible">1</property>
+                        <property name="selection-mode">none</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
           </object>
         </child>
         <child>
           <object class="GtkLabel">
             <property name="visible">1</property>
-            <property name="label" translatable="yes">Units</property>
+            <property name="label" translatable="yes">Amount</property>
             <property name="xalign">0</property>
             <style> <class name="dim-label"/> </style>
           </object>
         </child>
         <child>
-          <object class="GtkComboBoxText" id="new_ingredient_unit">
+          <object class="GtkBox">
             <property name="visible">1</property>
-            <property name="has-entry">1</property>
-            <items>
-              <item id="g" translatable="yes">grams</item>
-              <item id="kg" translatable="yes">kilograms</item>
-              <item id="lb" translatable="yes">pounds</item>
-            </items>
+            <property name="orientation">horizontal</property>
+            <style> <class name="linked"/> </style>
+            <child>
+              <object class="GtkEntry" id="new_ingredient_amount">
+                <property name="visible">1</property>
+                <property name="width-chars">6</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkComboBoxText" id="new_ingredient_unit">
+                <property name="visible">1</property>
+                <property name="has-entry">1</property>
+                <items>
+                  <item id="g" translatable="yes">grams</item>
+                  <item id="kg" translatable="yes">kilograms</item>
+                  <item id="lb" translatable="yes">pounds</item>
+                </items>
+              </object>
+            </child>
           </object>
         </child>
         <child>
@@ -686,11 +749,4 @@
       </object>
     </child>
   </object>
-  <object class="GtkAdjustment" id="amount_adjustment">
-    <property name="lower">0</property>
-    <property name="upper">1000</property>
-    <property name="page_size">0</property>
-    <property name="step_increment">1</property>
-    <property name="page_increment">10</property>
-  </object>
 </interface>


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