[glade/stack] Many GtkStack fixes



commit e533231f471afa029667983324ac9854217ba1b1
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Nov 10 22:28:21 2014 -0500

    Many GtkStack fixes
    
    Implement all of the required adaptor functions, add a virtual
    'page' property and use it instead of visible-child-name to switch
    between the pages to edit.

 plugins/gtk+/glade-gtk-stack.c     |  421 +++++++++++++++++++++++++++++++++++-
 plugins/gtk+/glade-stack-editor.ui |   61 ++++--
 plugins/gtk+/gtk+.xml.in           |   21 ++
 3 files changed, 480 insertions(+), 23 deletions(-)
---
diff --git a/plugins/gtk+/glade-gtk-stack.c b/plugins/gtk+/glade-gtk-stack.c
index 99ba5df..c71ae08 100644
--- a/plugins/gtk+/glade-gtk-stack.c
+++ b/plugins/gtk+/glade-gtk-stack.c
@@ -33,6 +33,7 @@ glade_gtk_stack_selection_changed (GladeProject * project,
   GList *list;
   GtkWidget *page, *sel_widget;
   GtkStack *stack = GTK_STACK (glade_widget_get_object (gwidget));
+  gint position;
 
   if ((list = glade_project_selection_get (project)) != NULL &&
       g_list_length (list) == 1)
@@ -52,6 +53,8 @@ glade_gtk_stack_selection_changed (GladeProject * project,
                   gtk_widget_is_ancestor (sel_widget, page))
                 {
                   gtk_stack_set_visible_child (stack, page);
+                  gtk_container_child_get (GTK_CONTAINER (stack), page, "position", &position, NULL);
+                  glade_widget_property_set (gwidget, "page", position);
                   break;
                 }
             }
@@ -89,9 +92,7 @@ glade_gtk_stack_post_create (GladeWidgetAdaptor *adaptor,
   GladeWidget *gwidget = glade_widget_get_from_gobject (container);
 
   if (reason == GLADE_CREATE_USER)
-    gtk_stack_add_named (GTK_STACK (container),
-                         glade_placeholder_new (),
-                         "page0");
+    gtk_stack_add_named (GTK_STACK (container), glade_placeholder_new (), "page0");
 
   g_signal_connect (G_OBJECT (gwidget), "notify::project",
                     G_CALLBACK (glade_gtk_stack_project_changed), NULL);
@@ -100,6 +101,42 @@ glade_gtk_stack_post_create (GladeWidgetAdaptor *adaptor,
 
 }
 
+static gchar *
+get_unused_name (GtkStack *stack)
+{
+  gchar *name;
+  gint i;
+
+  i = 0;
+  while (TRUE)
+    {
+      name = g_strdup_printf ("page%d", i);
+      if (gtk_stack_get_child_by_name (stack, name) == NULL)
+        return name;
+      g_free (name);
+      i++;
+    }
+
+  return NULL;
+}
+
+static void
+update_position_with_command (GtkWidget *widget, gpointer data)
+{
+  GtkContainer *parent = data;
+  GladeWidget *gwidget;
+  GladeProperty *property;
+  gint position;
+
+  gwidget = glade_widget_get_from_gobject (widget);
+  if (!gwidget)
+    return;
+
+  property = glade_widget_get_pack_property (gwidget, "position");
+  gtk_container_child_get (parent, widget, "position", &position, NULL);
+  glade_command_set_property (property, position);
+}
+
 void
 glade_gtk_stack_child_action_activate (GladeWidgetAdaptor * adaptor,
                                        GObject * container,
@@ -109,9 +146,17 @@ glade_gtk_stack_child_action_activate (GladeWidgetAdaptor * adaptor,
   if (!strcmp (action_path, "insert_page_after") ||
       !strcmp (action_path, "insert_page_before"))
     {
+      GladeWidget *parent;
+      GladeProperty *property;
       gint position;
       gchar *name;
       GtkWidget *new_widget;
+      gint pages;
+
+      parent = glade_widget_get_from_gobject (container);
+      glade_widget_property_get (parent, "pages", &pages);
+
+      glade_command_push_group (_("Insert placeholder to %s"), glade_widget_get_name (parent));
 
       gtk_container_child_get (GTK_CONTAINER (container), GTK_WIDGET (object),
                                "position", &position, NULL);
@@ -119,17 +164,49 @@ glade_gtk_stack_child_action_activate (GladeWidgetAdaptor * adaptor,
       if (!strcmp (action_path, "insert_page_after"))
         position++;
 
-      name = g_strdup_printf ("page%d", position);
+      name = get_unused_name (GTK_STACK (container));
       new_widget = glade_placeholder_new ();
-
       gtk_stack_add_named (GTK_STACK (container), new_widget, name);
+      gtk_container_child_set (GTK_CONTAINER (container), new_widget,
+                               "position", position, NULL);
       gtk_stack_set_visible_child (GTK_STACK (container), new_widget);
 
+      property = glade_widget_get_property (parent, "pages");
+      glade_command_set_property (property, pages + 1);
+
+      gtk_container_forall (GTK_CONTAINER (container), update_position_with_command, container);
+
+      property = glade_widget_get_property (parent, "page");
+      glade_command_set_property (property, position);
+
+      glade_command_pop_group ();
+
       g_free (name);
     }
   else if (strcmp (action_path, "remove_page") == 0)
     {
-      gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (object)); 
+      GladeWidget *parent;
+      GladeProperty *property;
+      gint pages;
+      gint position;
+
+      parent = glade_widget_get_from_gobject (container);
+      glade_widget_property_get (parent, "pages", &pages);
+
+      glade_command_push_group (_("Remove placeholder from %s"), glade_widget_get_name (parent));
+      g_assert (GLADE_IS_PLACEHOLDER (object));
+      gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (object));
+
+      property = glade_widget_get_property (parent, "pages");
+      glade_command_set_property (property, pages - 1);
+
+      gtk_container_forall (GTK_CONTAINER (container), update_position_with_command, container);
+
+      glade_widget_property_get (parent, "page", &position);
+      property = glade_widget_get_property (parent, "page");
+      glade_command_set_property (property, position);
+
+      glade_command_pop_group ();
     }
   else
     GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_action_activate (adaptor,
@@ -148,3 +225,335 @@ glade_gtk_stack_create_editable (GladeWidgetAdaptor * adaptor,
   return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->create_editable (adaptor, type);
 }
 
+typedef struct {
+  gint size;
+  gboolean include_placeholders;
+} ChildData;
+
+static void
+count_child (GtkWidget *child, gpointer data)
+{
+  ChildData *cdata = data;
+
+  if (cdata->include_placeholders || !GLADE_IS_PLACEHOLDER (child))
+    cdata->size++;
+}
+
+static gint
+gtk_stack_get_n_pages (GtkStack *stack,
+                       gboolean  include_placeholders)
+{
+  ChildData data;
+
+  data.size = 0;
+  data.include_placeholders = include_placeholders;
+  gtk_container_forall (GTK_CONTAINER (stack), count_child, &data);
+  return data.size;
+}
+
+static GtkWidget *
+gtk_stack_get_nth_child (GtkStack *stack,
+                         gint      n)
+{
+  GList *children;
+  GtkWidget *child;
+
+  children = gtk_container_get_children (GTK_CONTAINER (stack));
+  child = g_list_nth_data (children, n);
+  g_list_free (children);
+
+  return child;
+}
+
+static void
+update_position (GtkWidget *widget, gpointer data)
+{
+  GtkContainer *parent = data;
+  GladeWidget *gwidget;
+  gint position;
+
+  gwidget = glade_widget_get_from_gobject (widget);
+  if (gwidget)
+    {
+      gtk_container_child_get (parent, widget, "position", &position, NULL);
+      glade_widget_pack_property_set (gwidget, "position", position);
+    }
+}
+
+static void
+glade_gtk_stack_set_n_pages (GObject * object,
+                             const GValue * value)
+{
+  GladeWidget *gbox;
+  GtkStack *stack;
+  GtkWidget *child;
+  gint new_size, i;
+  gint old_size;
+  gchar *name;
+  gint page;
+
+  stack = GTK_STACK (object);
+
+  new_size = g_value_get_int (value);
+  old_size = gtk_stack_get_n_pages (stack, TRUE);
+
+  if (old_size == new_size)
+    return;
+
+  for (i = old_size; i < new_size; i++)
+    {
+      name = get_unused_name (stack);
+      child = glade_placeholder_new ();
+      gtk_stack_add_named (stack, child, name);
+      g_free (name);
+    }
+
+  for (i = old_size; i > 0; i--)
+    {
+      if (old_size <= new_size)
+        break;
+      child = gtk_stack_get_nth_child (stack, i - 1);
+      if (GLADE_IS_PLACEHOLDER (child))
+        {
+          gtk_container_remove (GTK_CONTAINER (stack), child);
+          old_size--;
+        }
+    }
+
+  gtk_container_forall (GTK_CONTAINER (stack), update_position, stack);
+
+  gbox = glade_widget_get_from_gobject (stack);
+  glade_widget_property_get (gbox, "page", &page);
+  glade_widget_property_set (gbox, "page", page);
+}
+
+static void
+glade_gtk_stack_set_page (GObject *object,
+                          const GValue *value)
+{
+  gint new_page;
+  GList *children;
+  GtkWidget *child;
+
+  new_page = g_value_get_int (value);
+  children = gtk_container_get_children (GTK_CONTAINER (object));
+  child = g_list_nth_data (children, new_page);
+
+  if (child)
+    gtk_stack_set_visible_child (GTK_STACK (object), child);
+
+  g_list_free (children);
+}
+
+static gint
+gtk_stack_get_page (GtkStack *stack)
+{
+  GtkWidget *child;
+  gint page;
+
+  child = gtk_stack_get_visible_child (stack);
+  gtk_container_child_get (GTK_CONTAINER (stack), child, "position", &page, NULL);
+  return page;
+}
+
+void
+glade_gtk_stack_set_property (GladeWidgetAdaptor * adaptor,
+                              GObject * object,
+                              const gchar * id,
+                              const GValue * value)
+{
+  if (!strcmp (id, "pages"))
+    glade_gtk_stack_set_n_pages (object, value);
+  else if (!strcmp (id, "page"))
+    glade_gtk_stack_set_page (object, value);
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object, id, value);
+}
+
+void
+glade_gtk_stack_get_property (GladeWidgetAdaptor * adaptor,
+                              GObject * object,
+                              const gchar * id,
+                              GValue * value)
+{
+  if (!strcmp (id, "pages"))
+    {
+      g_value_reset (value);
+      g_value_set_int (value, gtk_stack_get_n_pages (GTK_STACK (object), TRUE));
+    }
+  else if (!strcmp (id, "page"))
+    {
+      g_value_reset (value);
+      g_value_set_int (value, gtk_stack_get_page (GTK_STACK (object)));
+    }
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->get_property (adaptor, object, id, value);
+}
+
+static void
+glade_gtk_stack_set_child_position (GObject * container,
+                                    GObject * child,
+                                    const GValue * value)
+{
+  static gboolean recursion = FALSE;
+  gint new_position, old_position;
+  GladeWidget *gbox;
+  gint page;
+
+  if (recursion)
+    return;
+
+  gtk_container_child_get (GTK_CONTAINER (container), GTK_WIDGET (child), "position", &old_position, NULL);
+  new_position = g_value_get_int (value);
+
+  if (old_position == new_position)
+    return;
+
+  recursion = TRUE;
+  gtk_container_child_set (GTK_CONTAINER (container), GTK_WIDGET (child),
+                           "position", new_position,
+                           NULL);
+  gtk_container_forall (GTK_CONTAINER (container), update_position, container);
+  recursion = FALSE;
+
+  gbox = glade_widget_get_from_gobject (container);
+  glade_widget_property_get (gbox, "page", &page);
+  glade_widget_property_set (gbox, "page", page);
+}
+
+void
+glade_gtk_stack_set_child_property (GladeWidgetAdaptor * adaptor,
+                                    GObject * container,
+                                    GObject * child,
+                                    const gchar * id,
+                                    GValue * value)
+{
+  if (!strcmp (id, "position"))
+    glade_gtk_stack_set_child_position (container, child, value);
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_set_property (adaptor, container, child, id, value);
+}
+
+static gboolean
+glade_gtk_stack_verify_n_pages (GObject * object,
+                                const GValue *value)
+{
+  gint new_size, old_size;
+
+  new_size = g_value_get_int (value);
+  old_size = gtk_stack_get_n_pages (GTK_STACK (object), FALSE);
+
+  return old_size <= new_size;
+}
+
+static gboolean
+glade_gtk_stack_verify_page (GObject *object,
+                             const GValue *value)
+{
+  gint page;
+  gint pages;
+
+  page = g_value_get_int (value);
+  pages = gtk_stack_get_n_pages (GTK_STACK (object), TRUE);
+
+  return 0 <= page && page < pages;
+}
+
+gboolean
+glade_gtk_stack_verify_property (GladeWidgetAdaptor * adaptor,
+                                 GObject * object,
+                                 const gchar * id,
+                                 const GValue * value)
+{
+  if (!strcmp (id, "pages"))
+    return glade_gtk_stack_verify_n_pages (object, value);
+  else if (!strcmp (id, "page"))
+    return glade_gtk_stack_verify_page (object, value);
+  else if (GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property)
+    return GWA_GET_CLASS (GTK_TYPE_CONTAINER)->verify_property (adaptor, object, id, value);
+
+  return TRUE;
+}
+
+void
+glade_gtk_stack_add_child (GladeWidgetAdaptor * adaptor,
+                           GObject * object,
+                           GObject * child)
+{
+  GladeWidget *gbox, *gchild;
+  gint pages, page;
+
+  if (!glade_widget_superuser () && !GLADE_IS_PLACEHOLDER (child))
+    {
+      GList *l, *children;
+
+      children = gtk_container_get_children (GTK_CONTAINER (object));
+
+      for (l = g_list_last (children); l; l = l->prev)
+        {
+          GtkWidget *widget = l->data;
+          if (GLADE_IS_PLACEHOLDER (widget))
+            {
+              gtk_container_remove (GTK_CONTAINER (object), widget);
+              break;
+            }
+        }
+      g_list_free (children);
+    }
+
+  gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (child));
+
+  gbox = glade_widget_get_from_gobject (object);
+  glade_widget_property_get (gbox, "pages", &pages);
+  glade_widget_property_set (gbox, "pages", pages);
+  glade_widget_property_get (gbox, "page", &page);
+  glade_widget_property_set (gbox, "page", page);
+
+  gchild = glade_widget_get_from_gobject (child);
+  if (gchild != NULL)
+    glade_widget_set_pack_action_visible (gchild, "remove_page", FALSE);
+}
+
+void
+glade_gtk_stack_remove_child (GladeWidgetAdaptor * adaptor,
+                              GObject * object,
+                              GObject * child)
+{
+  GladeWidget *gbox;
+  gint pages, page;
+
+  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
+
+  gbox = glade_widget_get_from_gobject (object);
+  glade_widget_property_get (gbox, "pages", &pages);
+  glade_widget_property_set (gbox, "pages", pages);
+  glade_widget_property_get (gbox, "page", &page);
+  glade_widget_property_set (gbox, "page", page);
+}
+
+void
+glade_gtk_stack_replace_child (GladeWidgetAdaptor * adaptor,
+                               GObject * container,
+                               GObject * current,
+                               GObject * new_widget)
+{
+  GladeWidget *gchild;
+  GladeWidget *gbox;
+  gint pages, page;
+
+  GWA_GET_CLASS (GTK_TYPE_CONTAINER)->replace_child (adaptor,
+                                                     container,
+                                                     current,
+                                                     new_widget);
+
+  gbox = glade_widget_get_from_gobject (container);
+  glade_widget_property_get (gbox, "pages", &pages);
+  glade_widget_property_set (gbox, "pages", pages);
+  glade_widget_property_get (gbox, "page", &page);
+  glade_widget_property_set (gbox, "page", page);
+
+  gchild = glade_widget_get_from_gobject (new_widget);
+  if (gchild != NULL)
+    glade_widget_set_pack_action_visible (gchild, "remove_page", FALSE);
+
+}
diff --git a/plugins/gtk+/glade-stack-editor.ui b/plugins/gtk+/glade-stack-editor.ui
index 59c6ab9..da553bf 100644
--- a/plugins/gtk+/glade-stack-editor.ui
+++ b/plugins/gtk+/glade-stack-editor.ui
@@ -65,32 +65,57 @@ Author: Matthias Clasen <mclasen redhat com>
           </packing>
         </child>
         <child>
-          <object class="GladePropertyLabel" id="visible_child_label">
+          <object class="GladePropertyLabel" id="pages_label">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">False</property>
             <property name="margin_left">12</property>
-            <property name="property_name">visible-child-name</property>
+            <property name="hexpand">False</property>
+            <property name="property_name">pages</property>
           </object>
           <packing>
             <property name="left_attach">0</property>
             <property name="top_attach">2</property>
             <property name="width">2</property>
-            <property name="height">1</property>
           </packing>
         </child>
         <child>
-          <object class="GladePropertyShell" id="visible_child_editor">
+          <object class="GladePropertyShell" id="pages_editor">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <property name="hexpand">True</property>
-            <property name="property_name">visible-child-name</property>
+            <property name="hexpand">False</property>
+            <property name="property_name">pages</property>
           </object>
           <packing>
             <property name="left_attach">2</property>
             <property name="top_attach">2</property>
             <property name="width">4</property>
-            <property name="height">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GladePropertyLabel" id="page_label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="hexpand">False</property>
+            <property name="property_name">page</property>
+          </object>
+          <packing>
+            <property name="left_attach">0</property>
+            <property name="top_attach">3</property>
+            <property name="width">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GladePropertyShell" id="page_editor">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">False</property>
+            <property name="property_name">page</property>
+          </object>
+          <packing>
+            <property name="left_attach">2</property>
+            <property name="top_attach">3</property>
+            <property name="width">4</property>
           </packing>
         </child>
         <child>
@@ -104,7 +129,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">3</property>
+            <property name="top_attach">4</property>
             <property name="width">2</property>
             <property name="height">1</property>
           </packing>
@@ -118,7 +143,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">3</property>
+            <property name="top_attach">4</property>
             <property name="width">1</property>
             <property name="height">1</property>
           </packing>
@@ -132,7 +157,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">3</property>
-            <property name="top_attach">3</property>
+            <property name="top_attach">4</property>
             <property name="width">1</property>
             <property name="height">1</property>
           </packing>
@@ -147,7 +172,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">4</property>
+            <property name="top_attach">5</property>
             <property name="width">2</property>
             <property name="height">1</property>
           </packing>
@@ -161,7 +186,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">4</property>
+            <property name="top_attach">5</property>
             <property name="width">4</property>
             <property name="height">1</property>
           </packing>
@@ -176,7 +201,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">0</property>
-            <property name="top_attach">5</property>
+            <property name="top_attach">6</property>
             <property name="width">2</property>
             <property name="height">1</property>
           </packing>
@@ -190,7 +215,7 @@ Author: Matthias Clasen <mclasen redhat com>
           </object>
           <packing>
             <property name="left_attach">2</property>
-            <property name="top_attach">5</property>
+            <property name="top_attach">6</property>
             <property name="width">4</property>
             <property name="height">1</property>
           </packing>
@@ -205,8 +230,10 @@ Author: Matthias Clasen <mclasen redhat com>
     </child>
     <child-editors>
       <editor id="embed"/>
-      <editor id="visible_child_label"/>
-      <editor id="visible_child_editor"/>
+      <editor id="pages_label"/>
+      <editor id="pages_editor"/>
+      <editor id="page_label"/>
+      <editor id="page_editor"/>
       <editor id="hhomogeneous_editor"/>
       <editor id="vhomogeneous_editor"/>
       <editor id="transition_type_label"/>
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index 3e5bd72..252ae0d 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -2458,13 +2458,34 @@
       <glade-widget-class name="GtkStack" generic-name="stack" _title="Stack" since="3.10">
         <create-editable-function>glade_gtk_stack_create_editable</create-editable-function>
         <post-create-function>glade_gtk_stack_post_create</post-create-function>
+        <add-child-function>glade_gtk_stack_add_child</add-child-function>
+        <remove-child-function>glade_gtk_stack_remove_child</remove-child-function>
+        <replace-child-function>glade_gtk_stack_replace_child</replace-child-function>
         
<child-action-activate-function>glade_gtk_stack_child_action_activate</child-action-activate-function>
+        <get-property-function>glade_gtk_stack_get_property</get-property-function>
+        <set-property-function>glade_gtk_stack_set_property</set-property-function>
+        <child-set-property-function>glade_gtk_stack_set_child_property</child-set-property-function>
+        <verify-function>glade_gtk_stack_verify_property</verify-function>
         <packing-actions>
           <action id="insert_page_before" _name="Insert Page Before" stock="list-add"/>
           <action id="insert_page_after" _name="Insert Page After" stock="list-add"/>
           <action id="remove_page" _name="Remove Page"  stock="list-remove"/>
         </packing-actions>
         <properties>
+          <property id="pages" _name="Number of pages" save="False" default="1" custom-layout="True">
+            <parameter-spec>
+              <type>GParamInt</type>
+              <min>1</min>
+            </parameter-spec>
+            <_tooltip>The number of pages in the stack</_tooltip>
+          </property>
+          <property id="page" _name="Edit page" save="False" default="0" custom-layout="True">
+            <parameter-spec>
+              <type>GParamInt</type>
+              <min>0</min>
+            </parameter-spec>
+            <_tooltip>Set the currently active page to edit, this property will not be saved</_tooltip>
+          </property>
           <property id="visible-child" save="False" disabled="True"/>
           <property id="visible-child-name" _name="Visible child" save="False" custom-layout="True"/>
           <property id="homogeneous" save="False" disabled="True"/>


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