gtk treeview with first row fixed in place



Hi,

Recently I wrote a mail to gtk-app-devel-list, because I have to write
a code which uses a treeview widget. This widget should have a fixed
first row (right below the column headers) which is not affected by
scrolling and this row would be used for filtering the treeview
(attached a picture showing what I want to achieve).

Since noone answered I thought noone knows how to to this, so I tried
to do this on my own. I managed to do it by modifying gtktreeview.c
and gtktreeviewcolumn.c Since I'm not an experienced widget coder I
did it in a _really_ "hackish" way.

Attached the patch what I made, and this patch applies against ubuntu
hardy version of gtk (libgtk2.0-0
2.12.9-3ubuntu5)

I would really-really appreciate if some more experienced treeview
hacker could check this patch out and give me some advices how to
improve it, and maybe make it to reach the gtk mainline.

I think it would be really good if the treeview widget itself could
provide this kind of filtering functionality.

The patch itself does nothing special, It just places the header
button inside a vbox, so the user could use the get_widget method
(that is what I'm using for inserting comboboxentrys), and ask for
that parent till it reaches the vbox and can insert anything inside
that vbox.

Cheers,
Balazs Tirpak

Attachment: treeview.png
Description: PNG image

diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index de13b14..b387656 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -1707,9 +1707,9 @@ gtk_tree_view_map_buttons (GtkTreeView *tree_view)
       for (list = tree_view->priv->columns; list; list = list->next)
 	{
 	  column = list->data;
-          if (GTK_WIDGET_VISIBLE (column->button) &&
-              !GTK_WIDGET_MAPPED (column->button))
-            gtk_widget_map (column->button);
+          if (GTK_WIDGET_VISIBLE (gtk_widget_get_parent(column->button)) &&
+              !GTK_WIDGET_MAPPED (gtk_widget_get_parent(column->button)))
+            gtk_widget_map (gtk_widget_get_parent(column->button));
 	}
       for (list = tree_view->priv->columns; list; list = list->next)
 	{
@@ -1972,7 +1972,7 @@ gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
 
           column = list->data;
 	  
-          gtk_widget_size_request (column->button, &requisition);
+          gtk_widget_size_request (gtk_widget_get_parent(column->button), &requisition);
 	  column->button_request = requisition.width;
           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
         }
@@ -2279,7 +2279,7 @@ gtk_tree_view_size_allocate_columns (GtkWidget *widget)
       if (column->width > old_width)
         column_changed = TRUE;
 
-      gtk_widget_size_allocate (column->button, &allocation);
+      gtk_widget_size_allocate (gtk_widget_get_parent(column->button), &allocation);
 
       if (column->window)
 	gdk_window_move_resize (column->window,
@@ -2853,7 +2853,7 @@ gtk_tree_view_button_press (GtkWidget      *widget,
 					     drag_data);
 
 	  tree_view->priv->drag_pos = i;
-	  tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
+	  tree_view->priv->x_drag = gtk_widget_get_parent(column->button)->allocation.x + (rtl ? 0 : gtk_widget_get_parent(column->button)->allocation.width);
 
 	  if (!GTK_WIDGET_HAS_FOCUS (widget))
 	    gtk_widget_grab_focus (widget);
@@ -3657,7 +3657,7 @@ gtk_tree_view_motion_drag_column (GtkWidget      *widget,
   /* Handle moving the header */
   gdk_window_get_position (tree_view->priv->drag_window, &x, &y);
   x = CLAMP (x + (gint)event->x - column->drag_x, 0,
-	     MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
+	     MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - gtk_widget_get_parent(column->button)->allocation.width);
   gdk_window_move (tree_view->priv->drag_window, x, y);
   
   /* autoscroll, if needed */
@@ -4959,9 +4959,11 @@ gtk_tree_view_expose (GtkWidget      *widget,
 	    continue;
 
 	  if (column->visible)
-	    gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
-					    column->button,
-					    event);
+            {
+              gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
+                                              gtk_widget_get_parent(column->button),
+                                              event);
+            }
 	}
     }
   else if (event->window == tree_view->priv->drag_window)
@@ -5249,7 +5251,7 @@ gtk_tree_view_key_press (GtkWidget   *widget,
                 column->resized_width = 0;
 
               if (column->min_width == -1)
-                column->resized_width = MAX (column->button->requisition.width,
+                column->resized_width = MAX (gtk_widget_get_parent(column->button)->requisition.width,
                                              column->resized_width);
               else
                 column->resized_width = MAX (column->min_width,
@@ -7495,7 +7497,7 @@ gtk_tree_view_remove (GtkContainer *container,
     {
       GtkTreeViewColumn *column;
       column = tmp_list->data;
-      if (column->button == widget)
+      if (gtk_widget_get_parent(column->button) == widget)
 	{
 	  gtk_widget_unparent (widget);
 	  return;
@@ -7536,7 +7538,7 @@ gtk_tree_view_forall (GtkContainer *container,
       column = tmp_list->data;
 
       if (column->button)
-	(* callback) (column->button, callback_data);
+	(* callback) (gtk_widget_get_parent(column->button), callback_data);
     }
 }
 
@@ -8941,8 +8943,8 @@ gtk_tree_view_clamp_column_visible (GtkTreeView       *tree_view,
   if (column == NULL)
     return;
 
-  x = column->button->allocation.x;
-  width = column->button->allocation.width;
+  x = gtk_widget_get_parent(column->button)->allocation.x;
+  width = gtk_widget_get_parent(column->button)->allocation.width;
 
   if (width > tree_view->priv->hadjustment->page_size)
     {
@@ -9347,10 +9349,10 @@ _gtk_tree_view_column_start_drag (GtkTreeView       *tree_view,
 
       attributes.window_type = GDK_WINDOW_CHILD;
       attributes.wclass = GDK_INPUT_OUTPUT;
-      attributes.x = column->button->allocation.x;
+      attributes.x = gtk_widget_get_parent(column->button)->allocation.x;
       attributes.y = 0;
-      attributes.width = column->button->allocation.width;
-      attributes.height = column->button->allocation.height;
+      attributes.width = gtk_widget_get_parent(column->button)->allocation.width;
+      attributes.height = gtk_widget_get_parent(column->button)->allocation.height;
       attributes.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
       attributes.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
       attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
@@ -10510,11 +10512,11 @@ gtk_tree_view_new_column_width (GtkTreeView *tree_view,
    */
   rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
   column = g_list_nth (tree_view->priv->columns, i)->data;
-  width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
+  width = rtl ? (gtk_widget_get_parent(column->button)->allocation.x + gtk_widget_get_parent(column->button)->allocation.width - *x) : (*x - gtk_widget_get_parent(column->button)->allocation.x);
  
   /* Clamp down the value */
   if (column->min_width == -1)
-    width = MAX (column->button->requisition.width,
+    width = MAX (gtk_widget_get_parent(column->button)->requisition.width,
 		 width);
   else
     width = MAX (column->min_width,
@@ -10522,7 +10524,7 @@ gtk_tree_view_new_column_width (GtkTreeView *tree_view,
   if (column->max_width != -1)
     width = MIN (width, column->max_width);
 
-  *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
+  *x = rtl ? (gtk_widget_get_parent(column->button)->allocation.x + gtk_widget_get_parent(column->button)->allocation.width - width) : (gtk_widget_get_parent(column->button)->allocation.x + width);
  
   return width;
 }
@@ -11020,7 +11022,7 @@ gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
 	  for (list = tree_view->priv->columns; list; list = list->next)
 	    {
 	      column = list->data;
-	      gtk_widget_unmap (column->button);
+	      gtk_widget_unmap (gtk_widget_get_parent(column->button));
 	    }
 	  gdk_window_hide (tree_view->priv->header_window);
 	}
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 9331b8f..d49f0b2 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -26,6 +26,7 @@
 #include "gtkbutton.h"
 #include "gtkalignment.h"
 #include "gtklabel.h"
+#include "gtkvbox.h"
 #include "gtkhbox.h"
 #include "gtkmarshalers.h"
 #include "gtkarrow.h"
@@ -799,7 +800,7 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
 {
   GtkTreeView *tree_view;
   GtkWidget *child;
-  GtkWidget *hbox;
+  GtkWidget *hbox, *vbox;
 
   tree_view = (GtkTreeView *) tree_column->tree_view;
 
@@ -811,11 +812,6 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
   gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
   gtk_widget_pop_composite_child ();
 
-  /* make sure we own a reference to it as well. */
-  if (tree_view->priv->header_window)
-    gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
-  gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
-
   g_signal_connect (tree_column->button, "event",
 		    G_CALLBACK (gtk_tree_view_column_button_event),
 		    tree_column);
@@ -850,8 +846,18 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
   gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
   gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
 
+  vbox = gtk_vbox_new (FALSE, 0);
+
+  /* make sure we own a reference to it as well. */
+  if (tree_view->priv->header_window)
+    gtk_widget_set_parent_window (vbox, tree_view->priv->header_window);
+  gtk_widget_set_parent (GTK_WIDGET(vbox), GTK_WIDGET (tree_view));
+
+  gtk_box_pack_start(GTK_BOX(vbox), tree_column->button, TRUE, TRUE, 0);
+
   gtk_widget_show (hbox);
   gtk_widget_show (tree_column->alignment);
+  gtk_widget_show (tree_column->button);
   gtk_tree_view_column_update_button (tree_column);
 }
 
@@ -987,7 +993,7 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
     {
       if (tree_column->visible)
 	{
-	  gtk_widget_show_now (tree_column->button);
+	  gtk_widget_show_now (gtk_widget_get_parent(tree_column->button));
 	  if (tree_column->window)
 	    {
 	      if (tree_column->resizable)
@@ -1250,10 +1256,10 @@ _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
   g_return_if_fail (tree_view->priv->header_window != NULL);
   g_return_if_fail (column->button != NULL);
 
-  gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
+  gtk_widget_set_parent_window (gtk_widget_get_parent(column->button), tree_view->priv->header_window);
 
   if (column->visible)
-    gtk_widget_show (column->button);
+    gtk_widget_show (gtk_widget_get_parent(column->button));
 
   attr.window_type = GDK_WINDOW_CHILD;
   attr.wclass = GDK_INPUT_ONLY;
@@ -1272,7 +1278,7 @@ _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
   attr.width = TREE_VIEW_DRAG_WIDTH;
   attr.height = tree_view->priv->header_height;
 
-  attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
+  attr.x = (gtk_widget_get_parent(column->button)->allocation.x + (rtl ? 0 : gtk_widget_get_parent(column->button)->allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
   column->window = gdk_window_new (tree_view->priv->header_window,
 				   &attr, attributes_mask);
   gdk_window_set_user_data (column->window, tree_view);
@@ -1329,7 +1335,7 @@ _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
 {
   if (column->tree_view && column->button)
     {
-      gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
+      gtk_container_remove (GTK_CONTAINER (column->tree_view), gtk_widget_get_parent(column->button));
     }
   if (column->property_changed_signal)
     {


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