[gtk+/combo-refactor: 21/47] Make GtkTreeMenu update menu item sensitivity when "apply-attributes" signal is fired for a row in t



commit 48c03a645f51ae56b55694c1959f3f2951f39c0c
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Wed Nov 24 13:49:12 2010 +0900

    Make GtkTreeMenu update menu item sensitivity when "apply-attributes" signal is fired for a row in the menu.

 gtk/gtktreemenu.c |  201 ++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 153 insertions(+), 48 deletions(-)
---
diff --git a/gtk/gtktreemenu.c b/gtk/gtktreemenu.c
index 9598032..7212087 100644
--- a/gtk/gtktreemenu.c
+++ b/gtk/gtktreemenu.c
@@ -82,6 +82,9 @@ static void       gtk_tree_menu_set_area                      (GtkTreeMenu
 							       GtkCellArea          *area);
 static GtkWidget *gtk_tree_menu_get_path_item                 (GtkTreeMenu          *menu,
 							       GtkTreePath          *path);
+static gboolean   gtk_tree_menu_path_in_menu                  (GtkTreeMenu          *menu,
+							       GtkTreePath          *path,
+							       gboolean             *header_item);
 static void       row_inserted_cb                             (GtkTreeModel         *model,
 							       GtkTreePath          *path,
 							       GtkTreeIter          *iter,
@@ -98,10 +101,15 @@ static void       row_changed_cb                              (GtkTreeModel
 							       GtkTreePath          *path,
 							       GtkTreeIter          *iter,
 							       GtkTreeMenu          *menu);
-
 static void       context_size_changed_cb                     (GtkCellAreaContext   *context,
 							       GParamSpec           *pspec,
 							       GtkWidget            *menu);
+static void       area_apply_attributes_cb                    (GtkCellArea          *area,
+							       GtkTreeModel         *tree_model,
+							       GtkTreeIter          *iter,
+							       gboolean              is_expander,
+							       gboolean              is_expanded,
+							       GtkTreeMenu          *menu);
 static void       item_activated_cb                           (GtkMenuItem          *item,
 							       GtkTreeMenu          *menu);
 static void       submenu_activated_cb                        (GtkTreeMenu          *submenu,
@@ -122,6 +130,7 @@ struct _GtkTreeMenuPrivate
   
   /* Signals */
   gulong               size_changed_id;
+  gulong               apply_attributes_id;
   gulong               row_inserted_id;
   gulong               row_deleted_id;
   gulong               row_reordered_id;
@@ -223,8 +232,8 @@ gtk_tree_menu_class_init (GtkTreeMenuClass *class)
   object_class->set_property = gtk_tree_menu_set_property;
   object_class->get_property = gtk_tree_menu_get_property;
 
-  widget_class->get_preferred_width            = gtk_tree_menu_get_preferred_width;
-  widget_class->get_preferred_height           = gtk_tree_menu_get_preferred_height;
+  widget_class->get_preferred_width  = gtk_tree_menu_get_preferred_width;
+  widget_class->get_preferred_height = gtk_tree_menu_get_preferred_height;
 
   tree_menu_signals[SIGNAL_MENU_ACTIVATE] =
     g_signal_new (I_("menu-activate"),
@@ -359,11 +368,11 @@ gtk_tree_menu_constructor (GType                  type,
     }
 
   priv->context = gtk_cell_area_create_context (priv->area);
+
   priv->size_changed_id = 
     g_signal_connect (priv->context, "notify",
 		      G_CALLBACK (context_size_changed_cb), menu);
 
-
   return object;
 }
 
@@ -633,41 +642,60 @@ gtk_tree_menu_get_path_item (GtkTreeMenu          *menu,
   return item;
 }
 
-static void
-row_inserted_cb (GtkTreeModel     *model,
-		 GtkTreePath      *path,
-		 GtkTreeIter      *iter,
-		 GtkTreeMenu      *menu)
+static gboolean
+gtk_tree_menu_path_in_menu (GtkTreeMenu  *menu,
+			    GtkTreePath  *path,
+			    gboolean     *header_item)
 {
   GtkTreeMenuPrivate *priv = menu->priv;
-  GtkTreePath        *parent_path;
-  gboolean            this_menu = FALSE;
-  gint               *indices, index, depth;
-
-  parent_path = gtk_tree_path_copy (path);
+  GtkTreePath        *parent_path = gtk_tree_path_copy (path);
+  gboolean            in_menu = FALSE;
+  gboolean            is_header = FALSE;
 
-  /* Check if the menu and the added iter are in root of the model */
-  if (gtk_tree_path_get_depth (parent_path) <= 1)
+  /* Check if the is in root of the model */
+  if (gtk_tree_path_get_depth (parent_path) == 1)
     {
       if (!priv->root)
-	this_menu = TRUE;
+	in_menu = TRUE;
     }
-  /* If we are a submenu, compare the path */
-  else if (priv->root)
+  /* If we are a submenu, compare the parent path */
+  else if (priv->root && gtk_tree_path_up (parent_path))
     {
       GtkTreePath *root_path =
 	gtk_tree_row_reference_get_path (priv->root);
 
       if (gtk_tree_path_compare (root_path, parent_path) == 0)
-	this_menu = TRUE;
+	in_menu = TRUE;
+
+      if (!in_menu && priv->menu_with_header && 
+	  gtk_tree_path_compare (root_path, path) == 0)
+	{
+	  in_menu   = TRUE;
+	  is_header = TRUE;
+	}
 
       gtk_tree_path_free (root_path);
     }
 
   gtk_tree_path_free (parent_path);
 
+  if (header_item)
+    *header_item = is_header;
+
+  return in_menu;
+}
+
+static void
+row_inserted_cb (GtkTreeModel     *model,
+		 GtkTreePath      *path,
+		 GtkTreeIter      *iter,
+		 GtkTreeMenu      *menu)
+{
+  GtkTreeMenuPrivate *priv = menu->priv;
+  gint               *indices, index, depth;
+
   /* If the iter should be in this menu then go ahead and insert it */
-  if (this_menu)
+  if (gtk_tree_menu_path_in_menu (menu, path, NULL))
     {
       GtkWidget *item;
 
@@ -706,34 +734,30 @@ row_deleted_cb (GtkTreeModel     *model,
 		GtkTreeMenu      *menu)
 {
   GtkTreeMenuPrivate *priv = menu->priv;
-  GtkTreePath        *root_path;
   GtkWidget          *item;
+  gboolean            header_item;
+  gboolean            in_menu;
 
-  /* If it's the root node we leave it to the parent menu to remove us
-   * from its menu */
-  if (priv->root)
-    {
-      root_path = gtk_tree_row_reference_get_path (priv->root);
+  in_menu = gtk_tree_menu_path_in_menu (menu, path, &header_item);
 
-      if (gtk_tree_path_compare (root_path, path) == 0)
-	{
-	  gtk_tree_path_free (root_path);
-	  return;
-	}
-    }
-
-  item = gtk_tree_menu_get_path_item (menu, path);
-  if (item)
+  /* If it's the header item we leave it to the parent menu 
+   * to remove us from its menu
+   */
+  if (!header_item && in_menu)
     {
-      if (priv->wrap_width > 0)
-	rebuild_menu (menu);
-      else
+      item = gtk_tree_menu_get_path_item (menu, path);
+      if (item)
 	{
-	  /* Get rid of the deleted item */
-	  gtk_widget_destroy (item);
-      
-	  /* Resize everything */
-	  gtk_cell_area_context_flush (menu->priv->context);
+	  if (priv->wrap_width > 0)
+	    rebuild_menu (menu);
+	  else
+	    {
+	      /* Get rid of the deleted item */
+	      gtk_widget_destroy (item);
+	      
+	      /* Resize everything */
+	      gtk_cell_area_context_flush (menu->priv->context);
+	    }
 	}
     }
 }
@@ -748,7 +772,7 @@ row_reordered_cb (GtkTreeModel    *model,
   GtkTreeMenuPrivate *priv = menu->priv;
   gboolean            this_menu = FALSE;
 
-  if (iter == NULL && priv->root == NULL)
+  if (path == NULL && priv->root == NULL)
     this_menu = TRUE;
   else if (priv->root)
     {
@@ -823,7 +847,7 @@ row_changed_cb (GtkTreeModel         *model,
 	    }
 	  else if (!has_header && item)
 	    {
-	      /* Destroy the header item and the following separator */
+	      /* Destroy the header item and then the following separator */
 	      gtk_widget_destroy (item);
 	      gtk_widget_destroy (GTK_MENU_SHELL (menu)->children->data);
 
@@ -873,6 +897,75 @@ context_size_changed_cb (GtkCellAreaContext  *context,
     gtk_widget_queue_resize (menu);
 }
 
+static gboolean
+area_is_sensitive (GtkCellArea *area)
+{
+  GList    *cells, *list;
+  gboolean  sensitive = FALSE;
+  
+  cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (area));
+
+  for (list = cells; list; list = list->next)
+    {
+      g_object_get (list->data, "sensitive", &sensitive, NULL);
+      
+      if (sensitive)
+	break;
+    }
+  g_list_free (cells);
+
+  return sensitive;
+}
+
+static void
+area_apply_attributes_cb (GtkCellArea          *area,
+			  GtkTreeModel         *tree_model,
+			  GtkTreeIter          *iter,
+			  gboolean              is_expander,
+			  gboolean              is_expanded,
+			  GtkTreeMenu          *menu)
+{
+  /* If the menu for this iter has a submenu */
+  GtkTreeMenuPrivate *priv = menu->priv;
+  GtkTreePath        *path;
+  GtkWidget          *item;
+  gboolean            is_header;
+  gboolean            sensitive;
+
+  path = gtk_tree_model_get_path (tree_model, iter);
+
+  if (gtk_tree_menu_path_in_menu (menu, path, &is_header))
+    {
+      item = gtk_tree_menu_get_path_item (menu, path);
+
+      /* If there is no submenu, go ahead and update item sensitivity,
+       * items with submenus are always sensitive */
+      if (!gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)))
+	{
+	  sensitive = area_is_sensitive (priv->area);
+
+	  gtk_widget_set_sensitive (item, sensitive);
+
+	  if (is_header)
+	    {
+	      /* For header items we need to set the sensitivity
+	       * of the following separator item 
+	       */
+	      if (GTK_MENU_SHELL (menu)->children && 
+		  GTK_MENU_SHELL (menu)->children->next)
+		{
+		  GtkWidget *separator = 
+		    GTK_MENU_SHELL (menu)->children->next->data;
+
+		  gtk_widget_set_sensitive (separator, sensitive);
+		}
+	    }
+	}
+    }
+
+  gtk_tree_path_free (path);
+}
+
 static void
 gtk_tree_menu_set_area (GtkTreeMenu *menu,
 			GtkCellArea *area)
@@ -880,12 +973,24 @@ gtk_tree_menu_set_area (GtkTreeMenu *menu,
   GtkTreeMenuPrivate *priv = menu->priv;
 
   if (priv->area)
-    g_object_unref (priv->area);
+    {
+      g_signal_handler_disconnect (priv->area,
+				   priv->apply_attributes_id);
+      priv->apply_attributes_id = 0;
+
+      g_object_unref (priv->area);
+    }
 
   priv->area = area;
 
   if (priv->area)
-    g_object_ref_sink (priv->area);
+    {
+      g_object_ref_sink (priv->area);
+
+      priv->apply_attributes_id =
+	g_signal_connect (priv->area, "apply-attributes",
+			  G_CALLBACK (area_apply_attributes_cb), menu);
+    }
 }
 
 static gboolean



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