[gtk+/combo-refactor: 18/49] Added gtk_tree_menu_set/get_tearoff to allow the root menu to have a tearoff item



commit 31b8ab33491a5208d8cff2c7b60aa26523694f6b
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Tue Nov 23 12:11:52 2010 +0900

    Added gtk_tree_menu_set/get_tearoff to allow the root menu to have a tearoff item
    
    Combo boxes expose an "add-tearoffs" feature to add a tearoff item to the root of the combo menu, added this feature to GtkTreeMenu to achieve this (and updated the testcase).

 gtk/gtktreemenu.c    |  129 ++++++++++++++++++++++++++++++++++++--------------
 gtk/gtktreemenu.h    |    3 +
 tests/testtreemenu.c |   15 ++++++
 3 files changed, 111 insertions(+), 36 deletions(-)
---
diff --git a/gtk/gtktreemenu.c b/gtk/gtktreemenu.c
index c1ad3cd..278bdc4 100644
--- a/gtk/gtktreemenu.c
+++ b/gtk/gtktreemenu.c
@@ -26,6 +26,7 @@
 #include "gtktreemenu.h"
 #include "gtkmarshalers.h"
 #include "gtkmenuitem.h"
+#include "gtktearoffmenuitem.h"
 #include "gtkseparatormenuitem.h"
 #include "gtkcellareabox.h"
 #include "gtkcellareacontext.h"
@@ -56,8 +57,6 @@ static void      gtk_tree_menu_get_preferred_width            (GtkWidget
 static void      gtk_tree_menu_get_preferred_height           (GtkWidget           *widget,
 							       gint                *minimum_size,
 							       gint                *natural_size);
-static void      gtk_tree_menu_size_allocate                  (GtkWidget           *widget,
-							       GtkAllocation       *allocation);
 
 /* GtkCellLayoutIface */
 static void      gtk_tree_menu_cell_layout_init               (GtkCellLayoutIface  *iface);
@@ -110,13 +109,15 @@ struct _GtkTreeMenuPrivate
   GDestroyNotify        header_destroy;
 
   guint32               menu_with_header : 1;
+  guint32               tearoff     : 1;
 };
 
 enum {
   PROP_0,
   PROP_MODEL,
   PROP_ROOT,
-  PROP_CELL_AREA
+  PROP_CELL_AREA,
+  PROP_TEAROFF
 };
 
 enum {
@@ -160,7 +161,6 @@ gtk_tree_menu_class_init (GtkTreeMenuClass *class)
 
   widget_class->get_preferred_width            = gtk_tree_menu_get_preferred_width;
   widget_class->get_preferred_height           = gtk_tree_menu_get_preferred_height;
-  widget_class->size_allocate                  = gtk_tree_menu_size_allocate;
 
   tree_menu_signals[SIGNAL_MENU_ACTIVATE] =
     g_signal_new (I_("menu-activate"),
@@ -196,6 +196,14 @@ gtk_tree_menu_class_init (GtkTreeMenuClass *class)
 							 GTK_TYPE_CELL_AREA,
 							 GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
+   g_object_class_install_property (object_class,
+                                    PROP_TEAROFF,
+                                    g_param_spec_boolean ("tearoff",
+							  P_("Tearoff"),
+							  P_("Whether the menu has a tearoff item"),
+							  FALSE,
+							  GTK_PARAM_READWRITE));
+
 
    g_type_class_add_private (object_class, sizeof (GtkTreeMenuPrivate));
 }
@@ -300,6 +308,10 @@ gtk_tree_menu_set_property (GObject            *object,
       gtk_tree_menu_set_area (menu, (GtkCellArea *)g_value_get_object (value));
       break;
 
+    case PROP_TEAROFF:
+      gtk_tree_menu_set_tearoff (menu, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -317,21 +329,25 @@ gtk_tree_menu_get_property (GObject            *object,
 
   switch (prop_id)
     {
-      case PROP_MODEL:
-        g_value_set_object (value, priv->model);
-        break;
-
-      case PROP_ROOT:
-        g_value_set_boxed (value, priv->root);
-        break;
+    case PROP_MODEL:
+      g_value_set_object (value, priv->model);
+      break;
+      
+    case PROP_ROOT:
+      g_value_set_boxed (value, priv->root);
+      break;
+      
+    case PROP_CELL_AREA:
+      g_value_set_object (value, priv->area);
+      break;
 
-      case PROP_CELL_AREA:
-	g_value_set_object (value, priv->area);
-	break;
+    case PROP_TEAROFF:
+      g_value_set_boolean (value, priv->tearoff);
+      break;
 
-      default:
-        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-        break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
 }
 
@@ -390,7 +406,6 @@ gtk_tree_menu_get_preferred_width (GtkWidget           *widget,
   g_signal_handler_block (priv->context, priv->size_changed_id);
 
   sync_reserve_submenu_size (menu);
-  gtk_cell_area_context_flush_preferred_width (priv->context);
 
   GTK_WIDGET_CLASS (gtk_tree_menu_parent_class)->get_preferred_width (widget, minimum_size, natural_size);
 
@@ -408,29 +423,12 @@ gtk_tree_menu_get_preferred_height (GtkWidget           *widget,
   g_signal_handler_block (priv->context, priv->size_changed_id);
 
   sync_reserve_submenu_size (menu);
-  gtk_cell_area_context_flush_preferred_height (priv->context);
 
   GTK_WIDGET_CLASS (gtk_tree_menu_parent_class)->get_preferred_height (widget, minimum_size, natural_size);
 
   g_signal_handler_unblock (priv->context, priv->size_changed_id);
 }
 
-static void
-gtk_tree_menu_size_allocate (GtkWidget           *widget,
-			     GtkAllocation       *allocation)
-{
-  GtkTreeMenu        *menu = GTK_TREE_MENU (widget);
-  GtkTreeMenuPrivate *priv = menu->priv;
-
-  /* flush the context allocation */
-  gtk_cell_area_context_flush_allocation (priv->context);
-
-  /* Leave it to the first cell area to allocate the size of priv->context, since
-   * we configure the menu to allocate all children the same width this works fine
-   */
-  GTK_WIDGET_CLASS (gtk_tree_menu_parent_class)->size_allocate (widget, allocation);
-}
-
 /****************************************************************
  *                      GtkCellLayoutIface                      *
  ****************************************************************/
@@ -546,6 +544,12 @@ row_inserted_cb (GtkTreeModel     *model,
       if (priv->menu_with_header)
 	index += 2;
 
+      /* Index after the tearoff item for the root menu if
+       * there is a tearoff item
+       */
+      if (priv->root == NULL && priv->tearoff)
+	index += 1;
+
       item = gtk_tree_menu_create_item (menu, iter, FALSE);
       gtk_menu_shell_insert (GTK_MENU_SHELL (menu), item, index);
 
@@ -764,7 +768,21 @@ gtk_tree_menu_populate (GtkTreeMenu *menu)
       gtk_tree_path_free (path);
     }
   else
-    valid = gtk_tree_model_iter_children (priv->model, &iter, NULL);
+    {
+      /* Tearoff menu items only go in the root menu */
+      if (priv->tearoff)
+	{
+	  menu_item = gtk_tearoff_menu_item_new ();
+	  gtk_widget_show (menu_item);
+
+	  /* Here if wrap_width > 0 then we need to attach the menu
+	   * item to span the entire first row of the grid menu */
+	  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
+	}
+
+
+      valid = gtk_tree_model_iter_children (priv->model, &iter, NULL);
+    }
 
   /* Create a menu item for every row at the current depth, add a GtkTreeMenu
    * submenu for iters/items that have children */
@@ -937,6 +955,45 @@ gtk_tree_menu_get_root (GtkTreeMenu *menu)
   return NULL;
 }
 
+gboolean
+gtk_tree_menu_get_tearoff (GtkTreeMenu *menu)
+{
+  GtkTreeMenuPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_TREE_MENU (menu), FALSE);
+
+  priv = menu->priv;
+
+  return priv->tearoff;
+}
+
+void
+gtk_tree_menu_set_tearoff (GtkTreeMenu *menu,
+			   gboolean     tearoff)
+{
+  GtkTreeMenuPrivate *priv;
+
+  g_return_if_fail (GTK_IS_TREE_MENU (menu));
+
+  priv = menu->priv;
+
+  if (priv->tearoff != tearoff)
+    {
+      priv->tearoff = tearoff;
+
+      /* Destroy all the menu items */
+      gtk_container_foreach (GTK_CONTAINER (menu), 
+			     (GtkCallback) gtk_widget_destroy, NULL);
+      
+      /* Populate again */
+      if (priv->model)
+	gtk_tree_menu_populate (menu);
+
+      g_object_notify (G_OBJECT (menu), "tearoff");
+    }
+}
+
+
 void
 gtk_tree_menu_set_row_separator_func (GtkTreeMenu          *menu,
 				      GtkTreeViewRowSeparatorFunc func,
diff --git a/gtk/gtktreemenu.h b/gtk/gtktreemenu.h
index 539613f..472c7ce 100644
--- a/gtk/gtktreemenu.h
+++ b/gtk/gtktreemenu.h
@@ -85,6 +85,9 @@ GtkTreeModel         *gtk_tree_menu_get_model                      (GtkTreeMenu
 void                  gtk_tree_menu_set_root                       (GtkTreeMenu         *menu,
 								    GtkTreePath         *path);
 GtkTreePath          *gtk_tree_menu_get_root                       (GtkTreeMenu         *menu);
+gboolean              gtk_tree_menu_get_tearoff                    (GtkTreeMenu          *menu);
+void                  gtk_tree_menu_set_tearoff                    (GtkTreeMenu          *menu,
+								    gboolean              tearoff);
 
 void                        gtk_tree_menu_set_row_separator_func   (GtkTreeMenu          *menu,
 								    GtkTreeViewRowSeparatorFunc func,
diff --git a/tests/testtreemenu.c b/tests/testtreemenu.c
index e514f47..7445147 100644
--- a/tests/testtreemenu.c
+++ b/tests/testtreemenu.c
@@ -272,6 +272,13 @@ submenu_headers_toggled (GtkToggleButton  *toggle,
 }
 
 static void
+tearoff_toggled (GtkToggleButton *toggle,
+		 GtkTreeMenu     *menu)
+{
+  gtk_tree_menu_set_tearoff (menu, gtk_toggle_button_get_active (toggle));
+}
+
+static void
 tree_menu (void)
 {
   GtkWidget *window, *widget;
@@ -347,6 +354,14 @@ tree_menu (void)
   g_signal_connect (G_OBJECT (widget), "toggled",
                     G_CALLBACK (submenu_headers_toggled), menu);
 
+  widget = gtk_check_button_new_with_label ("Tearoff menu");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
+  gtk_widget_show (widget);
+  gtk_box_pack_start (GTK_BOX (vbox), widget, FALSE, FALSE, 0);
+  
+  g_signal_connect (G_OBJECT (widget), "toggled",
+                    G_CALLBACK (tearoff_toggled), menu);
+
 
   gtk_container_add (GTK_CONTAINER (window), vbox);
 



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