[glade/popover] Initial GtkPopoverMenu support



commit 7f5f73d61ecc29efda4e72cbb984b01e3e3222c3
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Nov 19 07:17:53 2014 +0100

    Initial GtkPopoverMenu support
    
    Add GtkPopoverMenu with two virtual properties, one for the number
    of menus, and one for the currently edited menu.

 plugins/gtk+/Makefile.am                           |    1 +
 plugins/gtk+/glade-gtk-popover-menu.c              |  478 ++++++++++++++++++++
 plugins/gtk+/gtk+.xml.in                           |   32 ++
 plugins/gtk+/icons/16x16/Makefile.am               |    1 +
 plugins/gtk+/icons/16x16/widget-gtk-popover.png    |  Bin 276 -> 311 bytes
 .../gtk+/icons/16x16/widget-gtk-popovermenu.png    |  Bin 0 -> 276 bytes
 plugins/gtk+/icons/22x22/Makefile.am               |    1 +
 plugins/gtk+/icons/22x22/widget-gtk-popover.png    |  Bin 327 -> 326 bytes
 .../gtk+/icons/22x22/widget-gtk-popovermenu.png    |  Bin 0 -> 327 bytes
 9 files changed, 513 insertions(+), 0 deletions(-)
---
diff --git a/plugins/gtk+/Makefile.am b/plugins/gtk+/Makefile.am
index 19e13f7..86953ea 100644
--- a/plugins/gtk+/Makefile.am
+++ b/plugins/gtk+/Makefile.am
@@ -92,6 +92,7 @@ libgladegtk_la_SOURCES =              \
        glade-gtk-overlay.c             \
        glade-gtk-paned.c               \
        glade-gtk-popover.c             \
+       glade-gtk-popover-menu.c        \
        glade-gtk-progress-bar.c        \
        glade-gtk-radio-button.c        \
        glade-gtk-radio-menu-item.c     \
diff --git a/plugins/gtk+/glade-gtk-popover-menu.c b/plugins/gtk+/glade-gtk-popover-menu.c
new file mode 100644
index 0000000..b3bbcc6
--- /dev/null
+++ b/plugins/gtk+/glade-gtk-popover-menu.c
@@ -0,0 +1,478 @@
+/*
+ * glade-gtk-popovermenu.c - GladeWidgetAdaptor for GtkPopoverMenu
+ *
+ * Copyright (C) 2014 Red Hat, Inc
+ *
+ * Authors:
+ *      Matthias Clasen <mclasen redhat com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+#include <glib/gi18n-lib.h>
+#include <gladeui/glade.h>
+
+GObject *
+glade_gtk_popover_menu_constructor (GType type,
+                                    guint n_construct_properties,
+                                    GObjectConstructParam * construct_properties)
+{
+  GladeWidgetAdaptor *adaptor;
+  GObject *ret_obj;
+
+  ret_obj = GWA_GET_OCLASS (GTK_TYPE_CONTAINER)->constructor
+      (type, n_construct_properties, construct_properties);
+
+  adaptor = GLADE_WIDGET_ADAPTOR (ret_obj);
+
+  glade_widget_adaptor_action_remove (adaptor, "add_parent");
+  glade_widget_adaptor_action_remove (adaptor, "remove_parent");
+
+  return ret_obj;
+}
+
+static void
+glade_gtk_popover_menu_parse_finished (GladeProject * project,
+                                       GObject * object)
+{
+  GladeWidget *gbox;
+  gint submenus;
+
+  gbox = glade_widget_get_from_gobject (object);
+  glade_widget_property_get (gbox, "submenus", &submenus);
+  glade_widget_property_set (gbox, "submenus", submenus);
+}
+
+void
+glade_gtk_popover_menu_post_create (GladeWidgetAdaptor *adaptor,
+                                    GObject *container,
+                                    GladeCreateReason reason)
+{
+  GladeWidget *parent = glade_widget_get_from_gobject (container);
+  GladeProject *project = glade_widget_get_project (parent);
+
+  if (reason == GLADE_CREATE_LOAD)
+    {
+      g_signal_connect (project, "parse-finished",
+                        G_CALLBACK (glade_gtk_popover_menu_parse_finished),
+                        container);
+    }
+  else if (reason == GLADE_CREATE_USER)
+    {
+      gtk_container_add (GTK_CONTAINER (container), glade_placeholder_new ());
+    }
+}
+
+void
+glade_gtk_popover_menu_add_child (GladeWidgetAdaptor *adaptor,
+                                  GObject *parent,
+                                  GObject *child)
+{
+  gtk_container_add (GTK_CONTAINER (parent), GTK_WIDGET (child));
+
+  if (!glade_widget_superuser ())
+    {
+      GladeWidget *gbox;
+      gint submenus;
+
+      gbox = glade_widget_get_from_gobject (parent);
+
+      glade_widget_property_get (gbox, "submenus", &submenus);
+      glade_widget_property_set (gbox, "submenus", submenus);
+    }
+}
+
+void
+glade_gtk_popover_menu_remove_child (GladeWidgetAdaptor *adaptor,
+                                     GObject *parent,
+                                     GObject *child)
+{
+  gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (child));
+
+  if (!glade_widget_superuser ())
+    {
+      GladeWidget *gbox;
+      gint submenus;
+
+      gbox = glade_widget_get_from_gobject (parent);
+
+      glade_widget_property_get (gbox, "submenus", &submenus);
+      glade_widget_property_set (gbox, "submenus", submenus);
+    }
+}
+
+void
+glade_gtk_popover_menu_replace_child (GladeWidgetAdaptor * adaptor,
+                                      GObject * container,
+                                      GObject * current,
+                                      GObject * new_widget)
+{
+  gchar *visible;
+  gchar *name;
+  gint position;
+  GladeWidget *gwidget;
+
+  g_object_get (G_OBJECT (container), "visible-submenu", &visible, NULL);
+
+  gtk_container_child_get (GTK_CONTAINER (container),
+                           GTK_WIDGET (current),
+                           "submenu", &name,
+                           "position", &position,
+                           NULL);
+
+  gtk_container_add (GTK_CONTAINER (container), GTK_WIDGET (new_widget));
+  gtk_container_remove (GTK_CONTAINER (container), GTK_WIDGET (current));
+
+  gtk_container_child_set (GTK_CONTAINER (container),
+                           GTK_WIDGET (new_widget),
+                           "submenu", name,
+                           "position", position,
+                           NULL);
+
+  g_object_set (G_OBJECT (container), "visible-submenu", visible, NULL);
+
+  gwidget = glade_widget_get_from_gobject (new_widget);
+  if (gwidget)
+    {
+      glade_widget_pack_property_set (gwidget, "submenu", name);
+      glade_widget_pack_property_set (gwidget, "position", position);
+    }
+
+  g_free (visible);
+  g_free (name);
+}
+
+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
+count_children (GtkContainer *container,
+                gboolean      include_placeholders)
+{
+  ChildData data;
+
+  data.size = 0;
+  data.include_placeholders = include_placeholders;
+  gtk_container_foreach (container, count_child, &data);
+  return data.size;
+}
+
+static gchar *
+get_unused_name (GtkPopoverMenu *popover)
+{
+  gint i;
+  gchar *name = NULL;
+  GList *children, *l;
+  gboolean exists;
+
+  children = gtk_container_get_children (GTK_CONTAINER (popover));
+
+  i = g_list_length (children);
+  while (1)
+    {
+      name = g_strdup_printf ("submenu%d", i);
+      exists = FALSE;
+      for (l = children; l && !exists; l = l->next)
+        {
+          gchar *submenu;
+          gtk_container_child_get (GTK_CONTAINER (popover), GTK_WIDGET (l->data),
+                                   "submenu", &submenu, NULL);
+          if (!strcmp (submenu, name))
+            exists = TRUE;
+          g_free (submenu);
+        }
+      if (!exists)
+        break;
+
+      g_free (name);
+      i++;
+    }
+
+  g_list_free (children);
+
+  return name;
+}
+
+static void
+glade_gtk_popover_menu_set_submenus (GObject * object,
+                                     const GValue * value)
+{
+  GladeWidget *gbox;
+  GtkWidget *child;
+  gint new_size, i;
+  gint old_size;
+  gchar *name;
+  gint page;
+
+  new_size = g_value_get_int (value);
+  old_size = count_children (GTK_CONTAINER (object), TRUE);
+
+  if (old_size == new_size)
+    return;
+  else if (old_size < new_size)
+    {
+      for (i = old_size; i < new_size; i++)
+        {
+          name = get_unused_name (GTK_POPOVER_MENU (object));
+          child = glade_placeholder_new ();
+          gtk_container_add_with_properties (GTK_CONTAINER (object), child,
+                                             "submenu", name, NULL);
+          g_free (name);
+        }
+    }
+  else
+    {
+      GList *children, *l;
+
+      children = gtk_container_get_children (GTK_CONTAINER (object));
+      for (l = g_list_last (children); l; l = l->prev)
+        {
+          if (old_size <= new_size)
+            break;
+      
+          child = l->data;
+          if (GLADE_IS_PLACEHOLDER (child))
+            {
+              gtk_container_remove (GTK_CONTAINER (object), child);
+              old_size--;
+            }
+        }
+    }
+
+  gbox = glade_widget_get_from_gobject (object);
+  glade_widget_property_get (gbox, "current", &page);
+  glade_widget_property_set (gbox, "current", page);
+}
+
+static void
+glade_gtk_popover_menu_set_current (GObject *object,
+                                    const GValue *value)
+{
+  gint new_page;
+  GList *children;
+  GtkWidget *child;
+  gchar *submenu;
+
+  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_container_child_get (GTK_CONTAINER (object), child,
+                               "submenu", &submenu,
+                               NULL);
+      gtk_popover_menu_open_submenu (GTK_POPOVER_MENU (object), submenu);
+      g_free (submenu);
+    }
+
+  g_list_free (children);
+}
+
+void
+glade_gtk_popover_menu_set_property (GladeWidgetAdaptor * adaptor,
+                                     GObject * object,
+                                     const gchar * id,
+                                     const GValue * value)
+{
+  if (!strcmp (id, "submenus"))
+    glade_gtk_popover_menu_set_submenus (object, value);
+  else if (!strcmp (id, "current"))
+    glade_gtk_popover_menu_set_current (object, value);
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->set_property (adaptor, object, id, value);
+}
+
+static gint
+get_visible_child (GtkPopoverMenu *popover)
+{
+  gchar *visible;
+  GList *children, *l;
+  gint ret, i;
+
+  ret = -1;
+
+  g_object_get (G_OBJECT (popover), "visible-submenu", &visible, NULL);
+  children = gtk_container_get_children (GTK_CONTAINER (popover));
+  for (l = children, i = 0; l; l = l->next, i++)
+    {
+      GtkWidget *child = l->data;
+      gchar *name;
+      gboolean found;
+
+      gtk_container_child_get (GTK_CONTAINER (popover), child, "submenu", &name, NULL);
+      found = !strcmp (visible, name);
+      g_free (name);
+      if (found)
+        {
+          ret = i;
+          break;
+        }
+    }
+  g_list_free (children);
+  g_free (visible);
+
+  return ret;
+}
+
+void
+glade_gtk_popover_menu_get_property (GladeWidgetAdaptor * adaptor,
+                                     GObject * object,
+                                     const gchar * id,
+                                     GValue * value)
+{
+  if (!strcmp (id, "submenus"))
+    {
+      g_value_reset (value);
+      g_value_set_int (value, count_children (GTK_CONTAINER (object), TRUE));
+    } 
+  else if (!strcmp (id, "current"))
+    {
+      g_value_reset (value);
+      g_value_set_int (value, get_visible_child (GTK_POPOVER_MENU (object)));
+    }
+  else
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->get_property (adaptor, object, id, value);
+}
+
+static gboolean
+glade_gtk_popover_menu_verify_submenus (GObject * object,
+                                        const GValue *value)
+{
+  gint new_size, old_size;
+
+  new_size = g_value_get_int (value);
+  old_size = count_children (GTK_CONTAINER (object), FALSE);
+
+  return old_size <= new_size;
+}
+
+static gboolean
+glade_gtk_popover_menu_verify_current (GObject *object,
+                                       const GValue *value)
+{
+  gint current;
+  gint submenus;
+
+  current = g_value_get_int (value);
+  submenus = count_children (GTK_CONTAINER (object), TRUE);
+
+  return 0 <= current && current < submenus;
+}
+
+gboolean
+glade_gtk_popover_menu_verify_property (GladeWidgetAdaptor * adaptor,
+                                        GObject * object,
+                                        const gchar * id,
+                                        const GValue * value)
+{
+  if (!strcmp (id, "submenus"))
+    return glade_gtk_popover_menu_verify_submenus (object, value);
+  else if (!strcmp (id, "current"))
+    return glade_gtk_popover_menu_verify_current (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;
+}
+
+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_popover_menu_set_child_position (GObject * container,
+                                           GObject * child,
+                                           GValue * value)
+{
+  static gboolean recursion = FALSE;
+  gint new_position, old_position;
+  gchar *visible_child;
+  GladeWidget *gbox;
+
+  g_object_get (container, "visible-submenu", &visible_child, NULL);
+
+  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)
+    {
+      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;
+    }
+
+  g_object_set (container, "visible-submenu", visible_child, NULL);
+  g_free (visible_child); 
+
+  gbox = glade_widget_get_from_gobject (container);
+  glade_widget_pack_property_set (gbox, "visible-submenu", get_visible_child (GTK_POPOVER_MENU (container)));
+}
+
+void
+glade_gtk_popover_menu_set_child_property (GladeWidgetAdaptor * adaptor,
+                                           GObject * container,
+                                           GObject * child,
+                                           const gchar * id,
+                                           GValue * value)
+{
+  if (!strcmp (id, "position"))
+    glade_gtk_popover_menu_set_child_position (container, child, value);
+  else if (!strcmp (id, "submenu"))
+    gtk_container_child_set_property (GTK_CONTAINER (container),
+                                      GTK_WIDGET (child), id, value);
+  else    
+    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_set_property (adaptor, container, child, id, value);
+}
+
+void
+glade_gtk_popover_menu_get_child_property (GladeWidgetAdaptor * adaptor,
+                                           GObject * container,
+                                           GObject * child,
+                                           const gchar * id,
+                                           GValue * value)
+{
+  gtk_container_child_get_property (GTK_CONTAINER (container),
+                                    GTK_WIDGET (child), id, value);
+}
+
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index 3b4a83e..c5791fc 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -3253,6 +3253,37 @@
         </properties>
       </glade-widget-class>
 
+      <glade-widget-class name="GtkPopoverMenu" generic-name="popovermenu" _title="Popover Menu">
+        <constructor-function>glade_gtk_popover_menu_constructor</constructor-function>
+        <post-create-function>glade_gtk_popover_menu_post_create</post-create-function>
+        <add-child-function>glade_gtk_popover_menu_add_child</add-child-function>
+        <remove-child-function>glade_gtk_popover_menu_remove_child</remove-child-function>
+        <replace-child-function>glade_gtk_popover_menu_replace_child</replace-child-function>
+        <get-property-function>glade_gtk_popover_menu_get_property</get-property-function>
+        <set-property-function>glade_gtk_popover_menu_set_property</set-property-function>
+        <verify-function>glade_gtk_popover_menu_verify_property</verify-function>
+        <child-set-property-function>glade_gtk_popover_menu_set_child_property</child-set-property-function>
+        <child-get-property-function>glade_gtk_popover_menu_get_child_property</child-get-property-function>
+
+        <properties>
+          <property id="visible-submenu" disabled="True"/>
+          <property id="submenus" _name="Number of submenus" save="False" default="1"> <!-- 
custom-layout="True" -->
+            <parameter-spec>
+              <type>GParamInt</type>
+              <min>1</min>
+            </parameter-spec>
+            <_tooltip>The number of submenus in the popover menu</_tooltip>
+          </property>
+          <property id="current" _name="Edit menu" save="False" default="0"> <!-- custom-layout="True" -->
+            <parameter-spec>
+              <type>GParamInt</type>
+              <min>0</min>
+            </parameter-spec>
+            <_tooltip>Set the currently active submenu to edit, this property will not be saved</_tooltip>
+          </property>
+        </properties>
+      </glade-widget-class>
+
       <glade-widget-class name="GtkLinkButton" generic-name="linkbutton" _title="Link Button">
         <properties>
           <!-- The pspec of this prop says that the default is http://www.gtk.org but gtk_link_button_init() 
does
@@ -5243,6 +5274,7 @@
       <glade-widget-class-ref name="GtkSearchBar" />
       <glade-widget-class-ref name="GtkHeaderBar" />
       <glade-widget-class-ref name="GtkPopover"/>
+      <glade-widget-class-ref name="GtkPopoverMenu"/>
     </glade-widget-group>
     
     <glade-widget-group name="gtk-control-display" _title="Control and Display">
diff --git a/plugins/gtk+/icons/16x16/Makefile.am b/plugins/gtk+/icons/16x16/Makefile.am
index 0a413af..d2e9b0a 100644
--- a/plugins/gtk+/icons/16x16/Makefile.am
+++ b/plugins/gtk+/icons/16x16/Makefile.am
@@ -80,6 +80,7 @@ icons_DATA = \
        widget-gtk-pagesetupdialog.png \
        widget-gtk-placessidebar.png \
        widget-gtk-popover.png \
+       widget-gtk-popovermenu.png \
        widget-gtk-printdialog.png \
        widget-gtk-progressbar.png \
        widget-gtk-searchbar.png \
diff --git a/plugins/gtk+/icons/16x16/widget-gtk-popover.png b/plugins/gtk+/icons/16x16/widget-gtk-popover.png
index 5f82f3c..154a77c 100644
Binary files a/plugins/gtk+/icons/16x16/widget-gtk-popover.png and 
b/plugins/gtk+/icons/16x16/widget-gtk-popover.png differ
diff --git a/plugins/gtk+/icons/16x16/widget-gtk-popovermenu.png 
b/plugins/gtk+/icons/16x16/widget-gtk-popovermenu.png
new file mode 100644
index 0000000..5f82f3c
Binary files /dev/null and b/plugins/gtk+/icons/16x16/widget-gtk-popovermenu.png differ
diff --git a/plugins/gtk+/icons/22x22/Makefile.am b/plugins/gtk+/icons/22x22/Makefile.am
index a1757b4..e54b2f3 100644
--- a/plugins/gtk+/icons/22x22/Makefile.am
+++ b/plugins/gtk+/icons/22x22/Makefile.am
@@ -80,6 +80,7 @@ icons_DATA = \
        widget-gtk-pagesetupdialog.png \
        widget-gtk-placessidebar.png \
        widget-gtk-popover.png \
+       widget-gtk-popovermenu.png \
        widget-gtk-printdialog.png \
        widget-gtk-progressbar.png \
        widget-gtk-searchbar.png \
diff --git a/plugins/gtk+/icons/22x22/widget-gtk-popover.png b/plugins/gtk+/icons/22x22/widget-gtk-popover.png
index ac5e04c..bc2d5d0 100644
Binary files a/plugins/gtk+/icons/22x22/widget-gtk-popover.png and 
b/plugins/gtk+/icons/22x22/widget-gtk-popover.png differ
diff --git a/plugins/gtk+/icons/22x22/widget-gtk-popovermenu.png 
b/plugins/gtk+/icons/22x22/widget-gtk-popovermenu.png
new file mode 100644
index 0000000..ac5e04c
Binary files /dev/null and b/plugins/gtk+/icons/22x22/widget-gtk-popovermenu.png differ


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