Re: Table menu patch for GtkMenu



On Tue, 2003-07-15 at 16:34, Owen Taylor wrote:
> The API is basically fine, though I'd like to see some explanation
> of what "gtk_menu_occupied" is for, but I have various large-scale

gtk_menu_occupied() was for checking if a given place is already
occupied by a menu item. But now I moved to child properties, as you
suggested, this function is no longer needed. So now it only appears as
a GtkComboBox internal.

> thoughts about the implementation:

I think I addressed all of your comments in the new patch, which I've
attached. Some notes:

- in the size requisition/allocation algorithm, the width is
homogeneous, but the height is not. Why is this? For example, think of a
menu with usual text items and a separator item. Then the separator item
*has* to have another height then the text items in order to look nice.

- Now we have child properties, we can basically drop the
gtk_menu_attach() function. In that case, we need to make GtkMenu to
connect to each notify signal of all of the attach properties. Do we
want to do this? Isn't this too much overhead? It doesn't sound like a
good idea to me.

I hope this new patch comes closer to what you are expecting.


thanks,


	-Kris
Index: gtkmenu.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.c,v
retrieving revision 1.134
diff -u -p -r1.134 gtkmenu.c
--- gtkmenu.c	13 Jul 2003 02:42:40 -0000	1.134
+++ gtkmenu.c	23 Jul 2003 23:17:07 -0000
@@ -74,10 +74,18 @@ struct _GtkMenuPrivate 
   gboolean have_position;
   gint x;
   gint y;
+
+  /* info used for the table */
+  guint rows;
+  guint columns;
+  GList *child_info;
+
+  guint *height;
 };
 
 enum {
   MOVE_SCROLL,
+  MOVE_LEFT_RIGHT,
   LAST_SIGNAL
 };
 
@@ -88,14 +96,14 @@ enum {
 
 static void     gtk_menu_class_init        (GtkMenuClass     *klass);
 static void     gtk_menu_init              (GtkMenu          *menu);
-static void     gtk_menu_set_property      (GObject      *object,
-					    guint         prop_id,
-					    const GValue *value,
-					    GParamSpec   *pspec);
-static void     gtk_menu_get_property      (GObject     *object,
-					    guint        prop_id,
-					    GValue      *value,
-					    GParamSpec  *pspec);
+static void     gtk_menu_set_property      (GObject          *object,
+					    guint             prop_id,
+					    const GValue     *value,
+					    GParamSpec       *pspec);
+static void     gtk_menu_get_property      (GObject          *object,
+					    guint             prop_id,
+					    GValue           *value,
+					    GParamSpec       *pspec);
 static void     gtk_menu_destroy           (GtkObject        *object);
 static void     gtk_menu_finalize          (GObject          *object);
 static void     gtk_menu_realize           (GtkWidget        *widget);
@@ -146,8 +154,15 @@ static void     gtk_menu_style_set      
 static gboolean gtk_menu_focus             (GtkWidget        *widget,
 					    GtkDirectionType direction);
 static gint     gtk_menu_get_popup_delay   (GtkMenuShell     *menu_shell);
+static void     gtk_menu_move_current      (GtkMenuShell     *menu_shell,
+                                            GtkMenuDirectionType direction);
 static void     gtk_menu_real_move_scroll  (GtkMenu          *menu,
 					    GtkScrollType     type);
+static GtkWidget *find_child               (GList            *children,
+                                            int               row,
+	                                    int               col);
+static void     gtk_menu_real_move_left_right (GtkMenu              *menu,
+                                               GtkMenuDirectionType  dir);
 
 static void     gtk_menu_stop_navigating_submenu       (GtkMenu          *menu);
 static gboolean gtk_menu_stop_navigating_submenu_cb    (gpointer          user_data);
@@ -179,6 +194,8 @@ static void _gtk_menu_refresh_accel_path
 static GtkMenuShellClass *parent_class = NULL;
 static const gchar	 *attach_data_key = "gtk-menu-attach-data";
 
+#define CHILD_INFO_KEY "gtk-menu-child-info"
+
 static guint menu_signals[LAST_SIGNAL] = { 0 };
 
 GtkMenuPrivate *
@@ -256,6 +273,15 @@ gtk_menu_class_init (GtkMenuClass *class
 			     _gtk_marshal_VOID__ENUM,
 			     G_TYPE_NONE, 1,
 			     GTK_TYPE_SCROLL_TYPE);
+  menu_signals[MOVE_LEFT_RIGHT] =
+    _gtk_binding_signal_new ("move_left_right",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                             G_CALLBACK (gtk_menu_real_move_left_right),
+                             NULL, NULL,
+                             _gtk_marshal_VOID__ENUM,
+                             G_TYPE_NONE, 1,
+                             GTK_TYPE_MENU_DIRECTION_TYPE);
   
   g_object_class_install_property (gobject_class,
                                    PROP_TEAROFF_TITLE,
@@ -319,6 +345,7 @@ gtk_menu_class_init (GtkMenuClass *class
   menu_shell_class->select_item = gtk_menu_select_item;
   menu_shell_class->insert = gtk_menu_real_insert;
   menu_shell_class->get_popup_delay = gtk_menu_get_popup_delay;
+  menu_shell_class->move_current = gtk_menu_move_current;
 
   binding_set = gtk_binding_set_by_class (class);
   gtk_binding_entry_add_signal (binding_set,
@@ -401,6 +428,16 @@ gtk_menu_class_init (GtkMenuClass *class
 				"move_scroll", 1,
 				GTK_TYPE_SCROLL_TYPE,
 				GTK_SCROLL_PAGE_DOWN);
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_Left, 0,
+                                "move_left_right", 1,
+                                GTK_TYPE_MENU_DIRECTION_TYPE,
+                                GTK_MENU_DIR_PREV);
+  gtk_binding_entry_add_signal (binding_set,
+                                GDK_Right, 0,
+                                "move_left_right", 1,
+                                GTK_TYPE_MENU_DIRECTION_TYPE,
+                                GTK_MENU_DIR_NEXT);
 
   gtk_settings_install_property (g_param_spec_boolean ("gtk-can-change-accels",
 						       _("Can change accelerators"),
@@ -768,10 +805,33 @@ gtk_menu_real_insert (GtkMenuShell     *
 		      GtkWidget        *child,
 		      gint              position)
 {
+  gint i;
+  GList *list;
+
   if (GTK_WIDGET_REALIZED (menu_shell))
     gtk_widget_set_parent_window (child, GTK_MENU (menu_shell)->bin_window);
 
   GTK_MENU_SHELL_CLASS (parent_class)->insert (menu_shell, child, position);
+
+  if (position < 0)
+    {
+      i = g_list_length (menu_shell->children) - 1;
+      gtk_menu_attach (GTK_MENU (menu_shell), child, 0, 1, i, i + 1);
+
+      return;
+    }
+
+  i = position;
+  list = g_list_nth (menu_shell->children, position);
+
+  do
+    {
+      gtk_menu_attach (GTK_MENU (menu_shell), list->data, 0, 1, i, i + 1);
+
+      list = list->next;
+      i++;
+    }
+  while (list);
 }
 
 static void
@@ -1020,7 +1080,6 @@ gtk_menu_popup (GtkMenu		    *menu,
 
   if (xgrab_shell == widget)
     popup_grab_on_window (widget->window, activate_time); /* Should always succeed */
-
   gtk_grab_add (GTK_WIDGET (menu));
 }
 
@@ -1534,6 +1593,7 @@ gtk_menu_realize (GtkWidget *widget)
   attributes.colormap = gtk_widget_get_colormap (widget);
   
   attributes.event_mask = gtk_widget_get_events (widget);
+
   attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |
 			    GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK );
   
@@ -1674,6 +1734,7 @@ static void
 gtk_menu_size_request (GtkWidget      *widget,
 		       GtkRequisition *requisition)
 {
+  gint i;
   GtkMenu *menu;
   GtkMenuShell *menu_shell;
   GtkWidget *child;
@@ -1682,12 +1743,14 @@ gtk_menu_size_request (GtkWidget      *w
   guint max_accel_width;
   guint vertical_padding;
   GtkRequisition child_requisition;
+  GtkMenuPrivate *priv;
   
   g_return_if_fail (GTK_IS_MENU (widget));
   g_return_if_fail (requisition != NULL);
   
   menu = GTK_MENU (widget);
   menu_shell = GTK_MENU_SHELL (widget);
+  priv = gtk_menu_get_private (menu);
   
   requisition->width = 0;
   requisition->height = 0;
@@ -1695,35 +1758,73 @@ gtk_menu_size_request (GtkWidget      *w
   max_toggle_size = 0;
   max_accel_width = 0;
   
+  g_free (priv->height);
+  priv->height = g_new0 (guint, priv->rows);
+
   children = menu_shell->children;
   while (children)
     {
+      gint toggle_size;
+      guint l, r, t, b;
+
       child = children->data;
       children = children->next;
       
-      if (GTK_WIDGET_VISIBLE (child))
-	{
-	  gint toggle_size;
+      if (! GTK_WIDGET_VISIBLE (child))
+        continue;
 
-          /* It's important to size_request the child
-           * before doing the toggle size request, in
-           * case the toggle size request depends on the size
-           * request of a child of the child (e.g. for ImageMenuItem)
-           */
-          
-	  GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
-	  gtk_widget_size_request (child, &child_requisition);
-	  
-	  requisition->width = MAX (requisition->width, child_requisition.width);
-	  requisition->height += child_requisition.height;
+      g_object_get (child,
+                    "left_attach", &l,
+                    "right_attach", &r,
+                    "top_attach", &t,
+                    "bottom_attach", &b,
+                    NULL);
+
+      /* It's important to size_request the child
+       * before doing the toggle size request, in
+       * case the toggle size request depends on the size
+       * request of a child of the child (e.g. for ImageMenuItem)
+       */
 
-	  gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
-	  max_toggle_size = MAX (max_toggle_size, toggle_size);
-	  max_accel_width = MAX (max_accel_width, GTK_MENU_ITEM (child)->accelerator_width);
-	}
+       GTK_MENU_ITEM (child)->show_submenu_indicator = TRUE;
+       gtk_widget_size_request (child, &child_requisition);
+
+       gtk_menu_item_toggle_size_request (GTK_MENU_ITEM (child), &toggle_size);
+       max_toggle_size = MAX (max_toggle_size, toggle_size);
+       max_accel_width = MAX (max_accel_width,
+                              GTK_MENU_ITEM (child)->accelerator_width);
+
+       /* handle all different span types */
+       if (l == (r - 1))
+         {
+           /* spans a single column */
+           requisition->width = MAX (requisition->width,
+                                     child_requisition.width);
+         }
+       else
+         {
+           gint part = child_requisition.width / (r - l);
+           requisition->width = MAX (requisition->width, part);
+         }
+
+
+       if (t == (b - 1))
+         {
+           /* spans a single row */
+           priv->height[t] = MAX (priv->height[t], child_requisition.height);
+         }
+       else
+         {
+           gint part = child_requisition.height / (b - t);
+           priv->height[t] = MAX (priv->height[t], part);
+         }
     }
 
+  for (i = 0; i < priv->rows; i++)
+    requisition->height += priv->height[i];
+
   requisition->width += max_toggle_size + max_accel_width;
+  requisition->width *= priv->columns;
   requisition->width += (GTK_CONTAINER (menu)->border_width +
 			 widget->style->xthickness) * 2;
 
@@ -1749,6 +1850,8 @@ gtk_menu_size_allocate (GtkWidget     *w
   GtkMenuShell *menu_shell;
   GtkWidget *child;
   GtkAllocation child_allocation;
+  GtkRequisition child_requisition;
+  GtkMenuPrivate *priv;
   GList *children;
   gint x, y;
   gint width, height;
@@ -1759,8 +1862,10 @@ gtk_menu_size_allocate (GtkWidget     *w
   
   menu = GTK_MENU (widget);
   menu_shell = GTK_MENU_SHELL (widget);
+  priv = gtk_menu_get_private (menu);
 
   widget->allocation = *allocation;
+  gtk_widget_get_child_requisition (GTK_WIDGET (menu), &child_requisition);
 
   gtk_widget_style_get (GTK_WIDGET (menu),
 			"vertical-padding", &vertical_padding,
@@ -1772,6 +1877,9 @@ gtk_menu_size_allocate (GtkWidget     *w
   width = MAX (1, allocation->width - x * 2);
   height = MAX (1, allocation->height - y * 2);
 
+  child_requisition.width -= x * 2;
+  child_requisition.height -= y * 2;
+
   if (menu_shell->active)
     gtk_menu_scroll_to (menu, menu->scroll_offset);
   
@@ -1799,41 +1907,60 @@ gtk_menu_size_allocate (GtkWidget     *w
 
   if (menu_shell->children)
     {
-      child_allocation.x = 0;
-      child_allocation.y = 0;
-      child_allocation.width = width;
-      
+      gint base_width = width / priv->columns;
+
       children = menu_shell->children;
       while (children)
 	{
 	  child = children->data;
 	  children = children->next;
-	  
+
 	  if (GTK_WIDGET_VISIBLE (child))
 	    {
-	      GtkRequisition child_requisition;
-	      gtk_widget_get_child_requisition (child, &child_requisition);
-	      
-	      child_allocation.height = child_requisition.height;
+              gint i;
+	      guint l, r, t, b;
+
+	      g_object_get (child,
+                            "left_attach", &l,
+                            "right_attach", &r,
+                            "top_attach", &t,
+                            "bottom_attach", &b,
+                            NULL);
+
+              child_allocation.width = (r - l) * base_width;
+              child_allocation.height = 0;
+              child_allocation.x = l * child_allocation.width;
+              child_allocation.y = 0;
+
+              for (i = 0; i < b; i++)
+                {
+                  if (i < t)
+                    child_allocation.y += priv->height[i];
+                  else
+                    child_allocation.height += priv->height[i];
+                }
 
 	      gtk_menu_item_toggle_size_allocate (GTK_MENU_ITEM (child),
 						  menu->toggle_size);
 
 	      gtk_widget_size_allocate (child, &child_allocation);
 	      gtk_widget_queue_draw (child);
-	      
-	      child_allocation.y += child_allocation.height;
 	    }
 	}
       
       /* Resize the item window */
       if (GTK_WIDGET_REALIZED (widget))
 	{
-	  gdk_window_resize (menu->bin_window,
-			     child_allocation.width,
-			     child_allocation.y);
-	}
+          gint i;
+          gint width, height;
+
+          for (i = 0; i < priv->rows; i++)
+            height += priv->height[i];
 
+          width = priv->columns * child_allocation.width;
+
+	  gdk_window_resize (menu->bin_window, width, height);
+	}
 
       if (menu->tearoff_active)
 	{
@@ -2978,6 +3105,7 @@ gtk_menu_scroll_item_visible (GtkMenuShe
 			      GtkWidget       *menu_item)
 {
   GtkMenu *menu;
+  GtkMenuPrivate *priv;
   gint child_offset, child_height;
   gint width, height;
   gint y;
@@ -2985,6 +3113,11 @@ gtk_menu_scroll_item_visible (GtkMenuShe
   gboolean last_child = 0;
   
   menu = GTK_MENU (menu_shell);
+  priv = gtk_menu_get_private (menu);
+
+  /* disable scrolling stuff for table menus */
+  if (priv->rows && priv->columns)
+    return;
 
   /* We need to check if the selected item fully visible.
    * If not we need to scroll the menu so that it becomes fully
@@ -3164,6 +3297,93 @@ gtk_menu_set_screen (GtkMenu   *menu, 
     }
 }
 
+static void
+gtk_menu_resize (GtkMenu *menu,
+                 guint    rows,
+		 guint    columns)
+{
+  GtkMenuPrivate *priv;
+
+  g_return_if_fail (rows > 0 && rows < 65536);
+  g_return_if_fail (columns > 0 && columns < 65536);
+
+  rows = MAX (rows, 1);
+  columns = MAX (columns, 1);
+
+  priv = gtk_menu_get_private (menu);
+
+  if (rows != priv->rows || columns != priv->columns)
+    {
+      GList *list;
+
+      for (list = priv->child_info; list; list = list->next)
+        {
+          guint b, r;
+
+          g_object_get (list->data,
+                        "bottom_attach", &b,
+                        "right_attach", &r,
+                        NULL);
+
+	  rows = MAX (rows, b);
+	  columns = MAX (columns, r);
+	}
+
+      if (rows != priv->rows)
+        {
+	  priv->rows = rows;
+	  /* FIXME: notify? */
+	}
+
+      if (columns != priv->columns)
+        {
+	  priv->columns = columns;
+	  /* FIXME: notify? */
+	}
+    }
+}
+
+void
+gtk_menu_attach (GtkMenu   *menu,
+                 GtkWidget *child,
+                 guint      left_attach,
+                 guint      right_attach,
+                 guint      top_attach,
+                 guint      bottom_attach)
+{
+  GList *i;
+  GtkMenuPrivate *priv;
+
+  g_return_if_fail (GTK_IS_MENU (menu));
+  g_return_if_fail (GTK_IS_MENU_ITEM (child));
+
+  g_return_if_fail (left_attach < right_attach);
+  g_return_if_fail (top_attach < bottom_attach);
+
+  for (i = GTK_MENU_SHELL (menu)->children; i; i = i->next)
+    if (i->data == child)
+      break;
+
+  if (!i)
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
+
+  priv = gtk_menu_get_private (menu);
+
+  g_object_set (child,
+                "left_attach", left_attach,
+                "right_attach", right_attach,
+                "top_attach", top_attach,
+                "bottom_attach", bottom_attach,
+                NULL);
+
+  if (right_attach >= priv->columns)
+    gtk_menu_resize (menu, priv->rows?priv->rows:1, right_attach);
+
+  if (bottom_attach >= priv->rows)
+    gtk_menu_resize (menu, bottom_attach, priv->columns?priv->columns:1);
+
+  gtk_widget_queue_draw (GTK_WIDGET (menu));
+}
 
 static gint
 gtk_menu_get_popup_delay (GtkMenuShell *menu_shell)
@@ -3177,6 +3397,79 @@ gtk_menu_get_popup_delay (GtkMenuShell *
   return popup_delay;
 }
 
+static void
+gtk_menu_move_current (GtkMenuShell *menu_shell,
+                       GtkMenuDirectionType direction)
+{
+  GtkMenuPrivate *priv = gtk_menu_get_private (GTK_MENU (menu_shell));
+
+  /* special case next/prev here if it's not a regular menu and also
+   * disable the regular left/right bindings
+   */
+  if (menu_shell->active_menu_item &&
+      (priv->rows > 1 || priv->columns > 1))
+    {
+      GtkWidget *match = NULL;
+      guint l, r, t, b;
+      int i;
+
+      g_object_get (menu_shell->active_menu_item,
+                    "left_attach", &l,
+                    "right_attach", &r,
+                    "top_attach", &t,
+                    "bottom_attach", &b,
+                    NULL);
+
+      if (direction == GTK_MENU_DIR_NEXT)
+        {
+	  for (i = b; i < priv->rows; i++)
+	    {
+	      match = find_child (menu_shell->children, i, l);
+	      if (match && _gtk_menu_item_is_selectable (match))
+		break;
+	    }
+
+	  if (!match)
+	    {
+	      /* wrap around */
+	      for (i = 0; i < b; i++)
+	        {
+		  match = find_child (menu_shell->children, i, l);
+		  if (match && _gtk_menu_item_is_selectable (match))
+		    break;
+		}
+	    }
+	}
+      else if (direction == GTK_MENU_DIR_PREV)
+        {
+	  for (i = t - 1; i >= 0; i--)
+	    {
+	      match = find_child (menu_shell->children, i, l);
+	      if (match && _gtk_menu_item_is_selectable (match))
+		break;
+	    }
+
+	  if (!match)
+	    {
+	      /* wrap around */
+	      for (i = priv->rows; i >= b; i--)
+	        {
+		  match = find_child (menu_shell->children, i, l);
+		  if (match && _gtk_menu_item_is_selectable (match))
+		    break;
+		}
+	    }
+	}
+
+      if (match)
+	gtk_menu_shell_select_item (menu_shell, match);
+
+      return;
+    }
+
+  GTK_MENU_SHELL_CLASS (parent_class)->move_current (menu_shell, direction);
+}
+
 static gint
 get_visible_size (GtkMenu *menu)
 {
@@ -3308,4 +3601,101 @@ gtk_menu_real_move_scroll (GtkMenu      
     default:
       break;
     }
+}
+
+static GtkWidget *
+find_child (GList *children,
+            int    row,
+	    int    col)
+{
+  GList *i;
+
+  for (i = children; i; i = i->next)
+    {
+      guint t, l;
+
+      g_object_get (i->data,
+                    "top_attach", &t,
+                    "left_attach", &l,
+                    NULL);
+
+      if (t == row && l == col)
+	return GTK_WIDGET (i->data);
+    }
+
+  return NULL;
+}
+
+static void
+gtk_menu_real_move_left_right (GtkMenu              *menu,
+                               GtkMenuDirectionType  dir)
+{
+  GtkMenuPrivate *priv;
+  GtkMenuShell *menu_shell = GTK_MENU_SHELL (menu);
+
+  gint i;
+  guint l, r, t, b;
+  GtkWidget *match = NULL;
+
+  if (!menu_shell->active_menu_item)
+    {
+      match = find_child (menu_shell->children, 0, 0);
+      if (match)
+        gtk_menu_shell_select_item (menu_shell, match);
+
+      return;
+    }
+
+  priv = gtk_menu_get_private (menu);
+
+  g_object_get (menu_shell->active_menu_item,
+                "left_attach", &l,
+                "right_attach", &r,
+                "top_attach", &t,
+                "bottom_attach", &b,
+                NULL);
+
+  if (dir == GTK_MENU_DIR_PREV)
+    {
+      for (i = l - 1; i >= 0; i--)
+        {
+          match = find_child (menu_shell->children, t, i);
+          if (match && _gtk_menu_item_is_selectable (match))
+            break;
+        }
+
+      if (!match)
+        {
+          /* wrap around */
+          for (i = priv->columns; i >= r; i--)
+            {
+              match = find_child (menu_shell->children, t, i);
+              if (match && _gtk_menu_item_is_selectable (match))
+                break;
+            }
+        }
+    }
+  else if (dir == GTK_MENU_DIR_NEXT)
+    {
+      for (i = r; i < priv->columns; i++)
+        {
+          match = find_child (menu_shell->children, t, i);
+          if (match && _gtk_menu_item_is_selectable (match))
+            break;
+        }
+
+      if (!match)
+        {
+          /* wrap around */
+          for (i = 0; i < r; i++)
+            {
+              match = find_child (menu_shell->children, t, i);
+              if (match && _gtk_menu_item_is_selectable (match))
+                break;
+            }
+        }
+    }
+
+  if (match)
+    gtk_menu_shell_select_item (GTK_MENU_SHELL (menu), match);
 }
Index: gtkmenu.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenu.h,v
retrieving revision 1.34
diff -u -p -r1.34 gtkmenu.h
--- gtkmenu.h	8 Nov 2002 19:41:42 -0000	1.34
+++ gtkmenu.h	23 Jul 2003 23:17:07 -0000
@@ -188,6 +188,19 @@ void       gtk_menu_reorder_child       
 
 void	   gtk_menu_set_screen		  (GtkMenu	       *menu,
 					   GdkScreen	       *screen);
+
+void       gtk_menu_attach                (GtkMenu             *menu,
+                                           GtkWidget           *child,
+                                           guint                left_attach,
+                                           guint                right_attach,
+                                           guint                top_attach,
+                                           guint                bottom_attach);
 #ifndef GTK_DISABLE_DEPRECATED
 #define gtk_menu_append(menu,child)	gtk_menu_shell_append  ((GtkMenuShell *)(menu),(child))
 #define gtk_menu_prepend(menu,child)    gtk_menu_shell_prepend ((GtkMenuShell *)(menu),(child))
Index: gtkmenuitem.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenuitem.c,v
retrieving revision 1.101
diff -u -p -r1.101 gtkmenuitem.c
--- gtkmenuitem.c	13 Jul 2003 02:42:40 -0000	1.101
+++ gtkmenuitem.c	23 Jul 2003 23:17:16 -0000
@@ -34,10 +34,12 @@
 #include "gtkmenubar.h"
 #include "gtkmenuitem.h"
 #include "gtkseparatormenuitem.h"
+#include "gtkintl.h"
 
 #define MENU_ITEM_CLASS(w)  GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
 
-enum {
+enum
+{
   ACTIVATE,
   ACTIVATE_ITEM,
   TOGGLE_SIZE_REQUEST,
@@ -45,9 +47,34 @@ enum {
   LAST_SIGNAL
 };
 
+enum
+{
+  PROP_0,
+  PROP_LEFT_ATTACH,
+  PROP_RIGHT_ATTACH,
+  PROP_TOP_ATTACH,
+  PROP_BOTTOM_ATTACH
+};
+
+struct _GtkMenuItemPrivate
+{
+  guint left_attach;
+  guint right_attach;
+  guint top_attach;
+  guint bottom_attach;
+};
+
 
 static void gtk_menu_item_class_init     (GtkMenuItemClass *klass);
 static void gtk_menu_item_init           (GtkMenuItem      *menu_item);
+static void gtk_menu_item_get_property   (GObject          *object,
+                                          guint             prop_id,
+                                          GValue           *value,
+                                          GParamSpec       *pspec);
+static void gtk_menu_item_set_property   (GObject          *object,
+                                          guint             prop_id,
+                                          const GValue     *value,
+                                          GParamSpec       *pspec);
 static void gtk_menu_item_destroy        (GtkObject        *object);
 static void gtk_menu_item_finalize       (GObject          *object);
 static void gtk_menu_item_size_request   (GtkWidget        *widget,
@@ -133,6 +160,8 @@ gtk_menu_item_class_init (GtkMenuItemCla
   parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->finalize = gtk_menu_item_finalize;
+  gobject_class->get_property = gtk_menu_item_get_property;
+  gobject_class->set_property = gtk_menu_item_set_property;
 
   object_class->destroy = gtk_menu_item_destroy;
 
@@ -234,6 +263,40 @@ gtk_menu_item_class_init (GtkMenuItemCla
 							     G_MAXINT,
 							     10,
 							     G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_LEFT_ATTACH,
+                                   g_param_spec_uint ("left_attach",
+                                                      _("Left Attach"),
+                                                      _("Left attach position of the menu item"),
+                                                      0, UINT_MAX, 0,
+                                                      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_RIGHT_ATTACH,
+                                   g_param_spec_uint ("right_attach",
+                                                      _("Right Attach"),
+                                                      _("Right attach position of the menu item"),
+                                                      0, UINT_MAX, 0,
+                                                      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_TOP_ATTACH,
+                                   g_param_spec_uint ("top_attach",
+                                                      _("Top Attach"),
+                                                      _("Top attach position of the menu item"),
+                                                      0, UINT_MAX, 0,
+                                                      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                                   PROP_BOTTOM_ATTACH,
+                                   g_param_spec_uint ("bottom_attach",
+                                                      _("Bottom Attach"),
+                                                      _("Bottom attach position of the menu item"),
+                                                      0, UINT_MAX, 0,
+                                                      G_PARAM_READWRITE));
+
+  g_type_class_add_private (gobject_class, sizeof (GtkMenuItemPrivate));
 }
 
 static void
@@ -253,6 +316,62 @@ gtk_menu_item_init (GtkMenuItem *menu_it
   menu_item->right_justify = FALSE;
 
   menu_item->timer = 0;
+}
+
+static void
+gtk_menu_item_set_property (GObject      *object,
+                            guint         prop_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GtkMenuItemPrivate *priv = GTK_MENU_ITEM_GET_PRIVATE (object);
+
+  switch (prop_id)
+    {
+      case PROP_LEFT_ATTACH:
+        priv->left_attach = g_value_get_uint (value);
+        break;
+      case PROP_RIGHT_ATTACH:
+        priv->right_attach = g_value_get_uint (value);
+        break;
+      case PROP_TOP_ATTACH:
+        priv->top_attach = g_value_get_uint (value);
+        break;
+      case PROP_BOTTOM_ATTACH:
+        priv->bottom_attach = g_value_get_uint (value);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
+}
+
+static void
+gtk_menu_item_get_property (GObject    *object,
+                            guint       prop_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GtkMenuItemPrivate *priv = GTK_MENU_ITEM_GET_PRIVATE (object);
+
+  switch (prop_id)
+    {
+      case PROP_LEFT_ATTACH:
+        g_value_set_uint (value, priv->left_attach);
+        break;
+      case PROP_RIGHT_ATTACH:
+        g_value_set_uint (value, priv->right_attach);
+        break;
+      case PROP_TOP_ATTACH:
+        g_value_set_uint (value, priv->top_attach);
+        break;
+      case PROP_BOTTOM_ATTACH:
+        g_value_set_uint (value, priv->bottom_attach);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+        break;
+    }
 }
 
 GtkWidget*
Index: gtkmenuitem.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmenuitem.h,v
retrieving revision 1.27
diff -u -p -r1.27 gtkmenuitem.h
--- gtkmenuitem.h	5 Oct 2002 01:51:16 -0000	1.27
+++ gtkmenuitem.h	23 Jul 2003 23:17:16 -0000
@@ -43,10 +43,12 @@ extern "C" {
 #define GTK_IS_MENU_ITEM(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_MENU_ITEM))
 #define GTK_IS_MENU_ITEM_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_MENU_ITEM))
 #define GTK_MENU_ITEM_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_MENU_ITEM, GtkMenuItemClass))
+#define GTK_MENU_ITEM_GET_PRIVATE(obj)  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_MENU_ITEM, GtkMenuItemPrivate))
 
 
-typedef struct _GtkMenuItem	  GtkMenuItem;
-typedef struct _GtkMenuItemClass  GtkMenuItemClass;
+typedef struct _GtkMenuItem	   GtkMenuItem;
+typedef struct _GtkMenuItemClass   GtkMenuItemClass;
+typedef struct _GtkMenuItemPrivate GtkMenuItemPrivate;
 
 struct _GtkMenuItem
 {


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