[recipes/inline-editing] More work in progress



commit 78726eb040528c817dada2b513c36a66cc0755e1
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Apr 19 13:10:54 2017 -0400

    More work in progress
    
    Add the overlay buttons back, and implement adding, removing
    and repositioning rows. Still to be done: editing, saving
    changes and other details.

 src/gr-edit-page.ui              |    1 +
 src/gr-ingredients-viewer-row.c  |  101 ++++++++++++++++++++++++++++++++++---
 src/gr-ingredients-viewer-row.ui |  100 ++++++++++++++++++++++++++++++++++++-
 src/gr-ingredients-viewer.c      |  104 +++++++++++++++++++++++++++++++++++++-
 src/gr-ingredients-viewer.ui     |    5 ++-
 5 files changed, 300 insertions(+), 11 deletions(-)
---
diff --git a/src/gr-edit-page.ui b/src/gr-edit-page.ui
index 6dcf5c6..cc63282 100644
--- a/src/gr-edit-page.ui
+++ b/src/gr-edit-page.ui
@@ -251,6 +251,7 @@
                     <child>
                       <object class="GtkButton">
                         <property name="visible">1</property>
+                        <property name="margin-top">20</property>
                         <property name="label" translatable="yes">Add List</property>
                         <signal name="clicked" handler="add_list2"/>
                       </object>
diff --git a/src/gr-ingredients-viewer-row.c b/src/gr-ingredients-viewer-row.c
index 9644d45..e580fbc 100644
--- a/src/gr-ingredients-viewer-row.c
+++ b/src/gr-ingredients-viewer-row.c
@@ -33,12 +33,14 @@ struct _GrIngredientsViewerRow
 
         GtkWidget *unit_label;
         GtkWidget *ingredient_label;
+        GtkWidget *buttons_stack;
 
         char *amount;
         char *unit;
         char *ingredient;
 
         gboolean editable;
+        gboolean active;
 
         GtkSizeGroup *group;
 };
@@ -51,9 +53,18 @@ enum {
         PROP_UNIT,
         PROP_INGREDIENT,
         PROP_SIZE_GROUP,
-        PROP_EDITABLE
+        PROP_EDITABLE,
+        PROP_ACTIVE
 };
 
+enum {
+        DELETE,
+        MOVE,
+        N_SIGNALS
+};
+
+static int signals[N_SIGNALS] = { 0, };
+
 static void
 gr_ingredients_viewer_row_finalize (GObject *object)
 {
@@ -98,6 +109,10 @@ gr_ingredients_viewer_row_get_property (GObject    *object,
                 g_value_set_boolean (value, self->editable);
                 break;
 
+          case PROP_ACTIVE:
+                g_value_set_boolean (value, self->active);
+                break;
+
           default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
           }
@@ -141,6 +156,33 @@ gr_ingredients_viewer_row_set_ingredient (GrIngredientsViewerRow *row,
 }
 
 static void
+gr_ingredients_viewer_row_set_size_group (GrIngredientsViewerRow *row,
+                                          GtkSizeGroup           *group)
+{
+        if (row->group)
+                gtk_size_group_remove_widget (row->group, row->unit_label);
+        g_set_object (&row->group, group);
+        if (row->group)
+                gtk_size_group_add_widget (row->group, row->unit_label);
+}
+
+static void
+gr_ingredients_viewer_row_set_editable (GrIngredientsViewerRow *row,
+                                        gboolean                editable)
+{
+        row->editable = editable;
+        gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), editable);
+}
+
+static void
+gr_ingredients_viewer_row_set_active (GrIngredientsViewerRow *row,
+                                      gboolean                active)
+{
+        row->active = active;
+        gtk_stack_set_visible_child_name (GTK_STACK (row->buttons_stack), active ? "buttons" : "empty");
+}
+
+static void
 gr_ingredients_viewer_row_set_property (GObject      *object,
                                        guint         prop_id,
                                        const GValue *value,
@@ -163,16 +205,15 @@ gr_ingredients_viewer_row_set_property (GObject      *object,
                 break;
 
           case PROP_SIZE_GROUP:
-                if (self->group)
-                        gtk_size_group_remove_widget (self->group, self->unit_label);
-                g_set_object (&self->group, g_value_get_object (value));
-                if (self->group)
-                        gtk_size_group_add_widget (self->group, self->unit_label);
+                gr_ingredients_viewer_row_set_size_group (self, g_value_get_object (value));
                 break;
 
           case PROP_EDITABLE:
-                self->editable = g_value_get_boolean (value);
-                gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (object), self->editable);
+                gr_ingredients_viewer_row_set_editable (self, g_value_get_boolean (value));
+                break;
+
+          case PROP_ACTIVE:
+                gr_ingredients_viewer_row_set_active (self, g_value_get_boolean (value));
                 break;
 
           default:
@@ -181,6 +222,24 @@ gr_ingredients_viewer_row_set_property (GObject      *object,
 }
 
 static void
+emit_delete (GrIngredientsViewerRow *row)
+{
+        g_signal_emit (row, signals[DELETE], 0);
+}
+
+static void
+emit_move_up (GrIngredientsViewerRow *row)
+{
+        g_signal_emit (row, signals[MOVE], 0, -1);
+}
+
+static void
+emit_move_down (GrIngredientsViewerRow *row)
+{
+        g_signal_emit (row, signals[MOVE], 0, 1);
+}
+
+static void
 gr_ingredients_viewer_row_class_init (GrIngredientsViewerRowClass *klass)
 {
         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
@@ -216,10 +275,36 @@ gr_ingredients_viewer_row_class_init (GrIngredientsViewerRowClass *klass)
                                       G_PARAM_READWRITE|G_PARAM_CONSTRUCT);
         g_object_class_install_property (object_class, PROP_EDITABLE, pspec);
 
+        pspec = g_param_spec_boolean ("active", NULL, NULL,
+                                      FALSE,
+                                      G_PARAM_READWRITE|G_PARAM_CONSTRUCT);
+        g_object_class_install_property (object_class, PROP_ACTIVE, pspec);
+
+        signals[DELETE] = g_signal_new ("delete",
+                                        G_TYPE_FROM_CLASS (object_class),
+                                        G_SIGNAL_RUN_FIRST,
+                                        0,
+                                        NULL, NULL,
+                                        NULL,
+                                        G_TYPE_NONE, 0);
+
+        signals[MOVE] = g_signal_new ("move",
+                                      G_TYPE_FROM_CLASS (object_class),
+                                      G_SIGNAL_RUN_FIRST,
+                                      0,
+                                      NULL, NULL,
+                                      NULL,
+                                      G_TYPE_NONE, 1, G_TYPE_INT);
+
         gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Recipes/gr-ingredients-viewer-row.ui");
 
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, unit_label);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, ingredient_label);
+        gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewerRow, buttons_stack);
+
+        gtk_widget_class_bind_template_callback (widget_class, emit_delete);
+        gtk_widget_class_bind_template_callback (widget_class, emit_move_up);
+        gtk_widget_class_bind_template_callback (widget_class, emit_move_down);
 }
 
 static void
diff --git a/src/gr-ingredients-viewer-row.ui b/src/gr-ingredients-viewer-row.ui
index e1c7413..5bc3418 100644
--- a/src/gr-ingredients-viewer-row.ui
+++ b/src/gr-ingredients-viewer-row.ui
@@ -6,7 +6,8 @@
       <object class="GtkBox" id="box">
         <property name="visible">1</property>
         <property name="spacing">12</property>
-        <property name="margin">6</property>
+        <property name="margin-start">6</property>
+        <property name="margin-end">6</property>
         <child>
           <object class="GtkLabel" id="unit_label">
             <property name="visible">1</property>
@@ -25,6 +26,103 @@
             <property name="expand">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkStack" id="buttons_stack">
+            <property name="visible">1</property>
+            <property name="halign">end</property>
+            <property name="transition-type">none</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">1</property>
+                <property name="opacity">0</property>
+              </object>
+              <packing>
+                <property name="name">empty</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox">
+                <property name="visible">1</property>
+                <property name="orientation">horizontal</property>
+                <property name="margin">4</property>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">1</property>
+                    <property name="relief">none</property>
+                    <signal name="clicked" handler="emit_move_up" swapped="yes"/>
+                    <style>
+                      <class name="image-button"/>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">1</property>
+                        <property name="icon-name">go-up-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">1</property>
+                    <property name="relief">none</property>
+                    <signal name="clicked" handler="emit_move_down" swapped="yes"/>
+                    <style>
+                      <class name="image-button"/>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">1</property>
+                        <property name="icon-name">go-down-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">1</property>
+                    <property name="relief">none</property>
+                    <style>
+                      <class name="image-button"/>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">1</property>
+                        <property name="icon-name">document-edit-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkButton">
+                    <property name="visible">1</property>
+                    <property name="relief">none</property>
+                    <signal name="clicked" handler="emit_delete" swapped="yes"/>
+                    <style>
+                      <class name="image-button"/>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">1</property>
+                        <property name="icon-name">user-trash-symbolic</property>
+                        <property name="icon-size">1</property>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="name">buttons</property>
+              </packing>
+            </child>
+          </object>
+        </child>
       </object>
     </child>
   </template>
diff --git a/src/gr-ingredients-viewer.c b/src/gr-ingredients-viewer.c
index 1530ca0..618aef0 100644
--- a/src/gr-ingredients-viewer.c
+++ b/src/gr-ingredients-viewer.c
@@ -27,6 +27,10 @@
 #include "gr-ingredients-list.h"
 #include "gr-utils.h"
 
+#ifdef ENABLE_GSPELL
+#include <gspell/gspell.h>
+#endif
+
 
 struct _GrIngredientsViewer
 {
@@ -34,6 +38,7 @@ struct _GrIngredientsViewer
 
         GtkWidget *title_stack;
         GtkWidget *title_entry;
+        GtkWidget *title_label;
         GtkWidget *list;
         GtkWidget *add_button;
 
@@ -42,6 +47,8 @@ struct _GrIngredientsViewer
         gboolean editable;
 
         GtkSizeGroup *group;
+
+        GtkWidget *active_row;
 };
 
 
@@ -69,6 +76,35 @@ gr_ingredients_viewer_finalize (GObject *object)
 }
 
 static void
+set_active_row (GrIngredientsViewer *viewer,
+                GtkWidget           *row)
+{
+        if (viewer->active_row)
+                g_object_set (viewer->active_row, "active", FALSE, NULL);
+        viewer->active_row = row;
+        if (viewer->active_row)
+                g_object_set (viewer->active_row, "active", TRUE, NULL);
+        // TODO: notify a property so other lists can unset theirs
+}
+
+static void
+selected_rows_changed (GtkListBox          *list,
+                       GrIngredientsViewer *viewer)
+{
+        GtkListBoxRow *row;
+
+        row = gtk_list_box_get_selected_row (list);
+        set_active_row (viewer, GTK_WIDGET (row));
+}
+
+static void
+title_changed (GtkEntry            *entry,
+               GrIngredientsViewer *viewer)
+{
+        // TODO mark page as unsaved
+}
+
+static void
 gr_ingredients_viewer_get_property (GObject    *object,
                                     guint       prop_id,
                                     GValue     *value,
@@ -102,6 +138,55 @@ gr_ingredients_viewer_get_property (GObject    *object,
 }
 
 static void
+delete_row (GrIngredientsViewerRow *row,
+            GrIngredientsViewer    *viewer)
+{
+        gtk_widget_destroy (GTK_WIDGET (row));
+        // TODO: mark page unsaved
+}
+
+static void
+move_row (GrIngredientsViewerRow *row,
+          int                     steps,
+          GrIngredientsViewer    *viewer)
+{
+        GtkWidget *list;
+        int index;
+
+        list = gtk_widget_get_parent (GTK_WIDGET (row));
+        index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (row));
+        gtk_list_box_unselect_row (GTK_LIST_BOX (list), GTK_LIST_BOX_ROW (row));
+
+        g_object_ref (row);
+        gtk_container_remove (GTK_CONTAINER (list), GTK_WIDGET (row));
+        gtk_list_box_insert (GTK_LIST_BOX (list), GTK_WIDGET (row), index + steps);
+        g_object_unref (row);
+
+        gtk_list_box_select_row (GTK_LIST_BOX (list), GTK_LIST_BOX_ROW (row));
+        // TODO: mark page unsaved
+}
+
+static void
+add_row (GtkButton           *button,
+         GrIngredientsViewer *viewer)
+{
+        GtkWidget *row;
+
+        row = g_object_new (GR_TYPE_INGREDIENTS_VIEWER_ROW,
+                            "amount", "",
+                            "unit", "",
+                            "ingredient", "",
+                            "size-group", viewer->group,
+                            "editable", viewer->editable,
+                            NULL);
+        g_signal_connect (row, "delete", G_CALLBACK (delete_row), viewer);
+        g_signal_connect (row, "move", G_CALLBACK (move_row), viewer);
+
+        gtk_container_add (GTK_CONTAINER (viewer->list), row);
+        // TODO mark page as unsaved
+}
+
+static void
 gr_ingredients_viewer_set_ingredients (GrIngredientsViewer *viewer,
                                        const char          *text)
 {
@@ -135,6 +220,8 @@ gr_ingredients_viewer_set_ingredients (GrIngredientsViewer *viewer,
                                     "size-group", viewer->group,
                                     "editable", viewer->editable,
                                     NULL);
+                g_signal_connect (row, "delete", G_CALLBACK (delete_row), viewer);
+                g_signal_connect (row, "move", G_CALLBACK (move_row), viewer);
 
                 gtk_container_add (GTK_CONTAINER (viewer->list), row);
         }
@@ -147,6 +234,7 @@ gr_ingredients_viewer_set_title (GrIngredientsViewer *viewer,
         g_free (viewer->title);
         viewer->title = g_strdup (title);
 
+        gtk_label_set_label (GTK_LABEL (viewer->title_label), title);
         gtk_entry_set_text (GTK_ENTRY (viewer->title_entry), title);
 }
 
@@ -156,6 +244,7 @@ gr_ingredients_viewer_set_editable (GrIngredientsViewer *viewer,
 {
         viewer->editable = editable;
         gtk_widget_set_visible (viewer->add_button, editable);
+        gtk_list_box_set_selection_mode (GTK_LIST_BOX (viewer->list), editable ? GTK_SELECTION_SINGLE : 
GTK_SELECTION_NONE);
 }
 
 static void
@@ -203,8 +292,16 @@ gr_ingredients_viewer_init (GrIngredientsViewer *self)
         gtk_list_box_set_header_func (GTK_LIST_BOX (self->list), all_headers, self, NULL);
 
         self->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
-}
 
+#if defined(ENABLE_GSPELL) && defined(GSPELL_TYPE_ENTRY)
+        {
+                GspellEntry *gspell_entry;
+                gspell_entry = gspell_entry_get_from_gtk_entry (GTK_ENTRY (self->title_entry));
+                gspell_entry_basic_setup (gspell_entry);
+        }
+#endif
+
+}
 
 static void
 gr_ingredients_viewer_class_init (GrIngredientsViewerClass *klass)
@@ -240,6 +337,11 @@ gr_ingredients_viewer_class_init (GrIngredientsViewerClass *klass)
         gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Recipes/gr-ingredients-viewer.ui");
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewer, title_stack);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewer, title_entry);
+        gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewer, title_label);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewer, list);
         gtk_widget_class_bind_template_child (widget_class, GrIngredientsViewer, add_button);
+
+        gtk_widget_class_bind_template_callback (widget_class, title_changed);
+        gtk_widget_class_bind_template_callback (widget_class, selected_rows_changed);
+        gtk_widget_class_bind_template_callback (widget_class, add_row);
 }
diff --git a/src/gr-ingredients-viewer.ui b/src/gr-ingredients-viewer.ui
index 6a3f2d8..dcb5bf6 100644
--- a/src/gr-ingredients-viewer.ui
+++ b/src/gr-ingredients-viewer.ui
@@ -7,7 +7,7 @@
       <object class="GtkStack" id="title_stack">
         <property name="visible">1</property>
         <child>
-          <object class="GtkLabel">
+          <object class="GtkLabel" id="title_label">
             <property name="visible">1</property>
             <property name="xalign">0</property>
             <property name="label" translatable="yes">Ingredients</property>
@@ -31,6 +31,7 @@
               <object class="GtkEntry" id="title_entry">
                 <property name="visible">1</property>
                 <property name="placeholder-text" translatable="yes">Name of the List</property>
+                <signal name="notify::text" handler="title_changed"/>
               </object>
               <packing>
                 <property name="expand">1</property>
@@ -53,6 +54,7 @@
       <object class="GtkListBox" id="list">
         <property name="visible">1</property>
         <property name="selection-mode">none</property>
+        <signal name="selected-rows-changed" handler="selected_rows_changed"/>
         <style>
           <class name="frame"/>
         </style>
@@ -78,6 +80,7 @@
         <property name="visible">1</property>
         <property name="halign">start</property>
         <property name="margin-top">10</property>
+        <signal name="clicked" handler="add_row"/>
         <style>
           <class name="dim-label"/>
         </style>


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