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) {