2 * Copyright (C) 2000 Red Hat, Inc., Jonathan Blandford <jrb@redhat.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "gtktreeviewcolumn.h"
21 #include "gtktreeview.h"
22 #include "gtktreeprivate.h"
23 #include "gtksignal.h"
24 #include "gtkbutton.h"
25 #include "gtkalignment.h"
28 #include "gtkmarshalers.h"
58 typedef struct _GtkTreeViewColumnCellInfo GtkTreeViewColumnCellInfo;
59 struct _GtkTreeViewColumnCellInfo
61 GtkCellRenderer *cell;
63 GtkTreeCellDataFunc func;
65 GtkDestroyNotify destroy;
71 guint in_editing_mode : 1;
75 static void gtk_tree_view_column_init (GtkTreeViewColumn *tree_column);
76 static void gtk_tree_view_column_class_init (GtkTreeViewColumnClass *klass);
79 static void gtk_tree_view_column_set_property (GObject *object,
83 static void gtk_tree_view_column_get_property (GObject *object,
87 static void gtk_tree_view_column_finalize (GObject *object);
89 /* Button handling code */
90 static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column);
91 static void gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column);
93 /* Button signal handlers */
94 static gint gtk_tree_view_column_button_event (GtkWidget *widget,
97 static void gtk_tree_view_column_button_clicked (GtkWidget *widget,
99 static gboolean gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
100 gboolean group_cycling,
103 /* Property handlers */
104 static void gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable,
105 GtkTreeViewColumn *tree_column);
107 /* Internal functions */
108 static void gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
110 static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column);
111 static void gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
112 GtkCellRenderer *cell_renderer,
114 static GtkTreeViewColumnCellInfo *gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
115 GtkCellRenderer *cell_renderer);
117 /* cell list manipulation */
118 static GList *gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column);
119 static GList *gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column);
120 static GList *gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column,
122 static GList *gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column,
124 static void gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
125 GtkTreeViewColumnCellInfo *info);
127 static GtkObjectClass *parent_class = NULL;
128 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
132 gtk_tree_view_column_get_type (void)
134 static GtkType tree_column_type = 0;
136 if (!tree_column_type)
138 static const GTypeInfo tree_column_info =
140 sizeof (GtkTreeViewColumnClass),
141 NULL, /* base_init */
142 NULL, /* base_finalize */
143 (GClassInitFunc) gtk_tree_view_column_class_init,
144 NULL, /* class_finalize */
145 NULL, /* class_data */
146 sizeof (GtkTreeViewColumn),
148 (GInstanceInitFunc) gtk_tree_view_column_init,
151 tree_column_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn", &tree_column_info, 0);
154 return tree_column_type;
158 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
160 GObjectClass *object_class;
162 object_class = (GObjectClass*) class;
164 parent_class = g_type_class_peek_parent (class);
166 class->clicked = NULL;
168 object_class->finalize = gtk_tree_view_column_finalize;
169 object_class->set_property = gtk_tree_view_column_set_property;
170 object_class->get_property = gtk_tree_view_column_get_property;
172 tree_column_signals[CLICKED] =
173 g_signal_new ("clicked",
174 GTK_CLASS_TYPE (object_class),
176 G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
178 _gtk_marshal_VOID__VOID,
181 g_object_class_install_property (object_class,
183 g_param_spec_boolean ("visible",
185 _("Whether to display the column"),
187 G_PARAM_READABLE | G_PARAM_WRITABLE));
189 g_object_class_install_property (object_class,
191 g_param_spec_boolean ("resizable",
193 _("Column is user-resizable"),
195 G_PARAM_READABLE | G_PARAM_WRITABLE));
197 g_object_class_install_property (object_class,
199 g_param_spec_int ("width",
201 _("Current width of the column"),
206 g_object_class_install_property (object_class,
208 g_param_spec_enum ("sizing",
210 _("Resize mode of the column"),
211 GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
212 GTK_TREE_VIEW_COLUMN_AUTOSIZE,
213 G_PARAM_READABLE | G_PARAM_WRITABLE));
215 g_object_class_install_property (object_class,
217 g_param_spec_int ("fixed_width",
219 _("Current fixed width of the column"),
223 G_PARAM_READABLE | G_PARAM_WRITABLE));
225 g_object_class_install_property (object_class,
227 g_param_spec_int ("min_width",
229 _("Minimum allowed width of the column"),
233 G_PARAM_READABLE | G_PARAM_WRITABLE));
235 g_object_class_install_property (object_class,
237 g_param_spec_int ("max_width",
239 _("Maximum allowed width of the column"),
243 G_PARAM_READABLE | G_PARAM_WRITABLE));
245 g_object_class_install_property (object_class,
247 g_param_spec_string ("title",
249 _("Title to appear in column header"),
251 G_PARAM_READABLE | G_PARAM_WRITABLE));
253 g_object_class_install_property (object_class,
255 g_param_spec_boolean ("clickable",
257 _("Whether the header can be clicked"),
259 G_PARAM_READABLE | G_PARAM_WRITABLE));
262 g_object_class_install_property (object_class,
264 g_param_spec_object ("widget",
266 _("Widget to put in column header button instead of column title"),
268 G_PARAM_READABLE | G_PARAM_WRITABLE));
270 g_object_class_install_property (object_class,
272 g_param_spec_float ("alignment",
274 _("X Alignment of the column header text or widget"),
278 G_PARAM_READABLE | G_PARAM_WRITABLE));
280 g_object_class_install_property (object_class,
282 g_param_spec_boolean ("reorderable",
284 _("Whether the column can be reordered around the headers"),
286 G_PARAM_READABLE | G_PARAM_WRITABLE));
288 g_object_class_install_property (object_class,
290 g_param_spec_boolean ("sort_indicator",
292 _("Whether to show a sort indicator"),
294 G_PARAM_READABLE | G_PARAM_WRITABLE));
296 g_object_class_install_property (object_class,
298 g_param_spec_enum ("sort_order",
300 _("Sort direction the sort indicator should indicate"),
303 G_PARAM_READABLE | G_PARAM_WRITABLE));
308 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
310 tree_column->button = NULL;
311 tree_column->xalign = 0.0;
312 tree_column->width = 0;
313 tree_column->requested_width = -1;
314 tree_column->min_width = -1;
315 tree_column->max_width = -1;
316 tree_column->resized_width = 0;
317 tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
318 tree_column->visible = TRUE;
319 tree_column->resizable = FALSE;
320 tree_column->clickable = FALSE;
321 tree_column->dirty = TRUE;
322 tree_column->sort_order = GTK_SORT_ASCENDING;
323 tree_column->show_sort_indicator = FALSE;
324 tree_column->property_changed_signal = 0;
325 tree_column->sort_clicked_signal = 0;
326 tree_column->sort_column_changed_signal = 0;
327 tree_column->sort_column_id = -1;
328 tree_column->reorderable = FALSE;
329 tree_column->maybe_reordered = FALSE;
330 tree_column->use_resized_width = FALSE;
334 gtk_tree_view_column_finalize (GObject *object)
336 GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
339 for (list = tree_column->cell_list; list; list = list->next)
341 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
345 GtkDestroyNotify d = info->destroy;
347 info->destroy = NULL;
350 gtk_tree_view_column_clear_attributes_by_info (tree_column, info);
351 g_object_unref (G_OBJECT (info->cell));
355 g_free (tree_column->title);
357 G_OBJECT_CLASS (parent_class)->finalize (object);
361 gtk_tree_view_column_set_property (GObject *object,
366 GtkTreeViewColumn *tree_column;
368 tree_column = GTK_TREE_VIEW_COLUMN (object);
373 gtk_tree_view_column_set_visible (tree_column,
374 g_value_get_boolean (value));
378 gtk_tree_view_column_set_resizable (tree_column,
379 g_value_get_boolean (value));
383 gtk_tree_view_column_set_sizing (tree_column,
384 g_value_get_enum (value));
387 case PROP_FIXED_WIDTH:
388 gtk_tree_view_column_set_fixed_width (tree_column,
389 g_value_get_int (value));
393 gtk_tree_view_column_set_min_width (tree_column,
394 g_value_get_int (value));
398 gtk_tree_view_column_set_max_width (tree_column,
399 g_value_get_int (value));
403 gtk_tree_view_column_set_title (tree_column,
404 g_value_get_string (value));
408 gtk_tree_view_column_set_clickable (tree_column,
409 g_value_get_boolean (value));
413 gtk_tree_view_column_set_widget (tree_column,
414 (GtkWidget*) g_value_get_object (value));
418 gtk_tree_view_column_set_alignment (tree_column,
419 g_value_get_float (value));
422 case PROP_REORDERABLE:
423 gtk_tree_view_column_set_reorderable (tree_column,
424 g_value_get_boolean (value));
427 case PROP_SORT_INDICATOR:
428 gtk_tree_view_column_set_sort_indicator (tree_column,
429 g_value_get_boolean (value));
432 case PROP_SORT_ORDER:
433 gtk_tree_view_column_set_sort_order (tree_column,
434 g_value_get_enum (value));
438 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
444 gtk_tree_view_column_get_property (GObject *object,
449 GtkTreeViewColumn *tree_column;
451 tree_column = GTK_TREE_VIEW_COLUMN (object);
456 g_value_set_boolean (value,
457 gtk_tree_view_column_get_visible (tree_column));
461 g_value_set_boolean (value,
462 gtk_tree_view_column_get_resizable (tree_column));
466 g_value_set_int (value,
467 gtk_tree_view_column_get_width (tree_column));
471 g_value_set_enum (value,
472 gtk_tree_view_column_get_sizing (tree_column));
475 case PROP_FIXED_WIDTH:
476 g_value_set_int (value,
477 gtk_tree_view_column_get_fixed_width (tree_column));
481 g_value_set_int (value,
482 gtk_tree_view_column_get_min_width (tree_column));
486 g_value_set_int (value,
487 gtk_tree_view_column_get_max_width (tree_column));
491 g_value_set_string (value,
492 gtk_tree_view_column_get_title (tree_column));
496 g_value_set_boolean (value,
497 gtk_tree_view_column_get_clickable (tree_column));
501 g_value_set_object (value,
502 (GObject*) gtk_tree_view_column_get_widget (tree_column));
506 g_value_set_float (value,
507 gtk_tree_view_column_get_alignment (tree_column));
510 case PROP_REORDERABLE:
511 g_value_set_boolean (value,
512 gtk_tree_view_column_get_reorderable (tree_column));
515 case PROP_SORT_INDICATOR:
516 g_value_set_boolean (value,
517 gtk_tree_view_column_get_sort_indicator (tree_column));
520 case PROP_SORT_ORDER:
521 g_value_set_enum (value,
522 gtk_tree_view_column_get_sort_order (tree_column));
526 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
534 /* Button handling code
537 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
539 GtkTreeView *tree_view;
543 tree_view = (GtkTreeView *) tree_column->tree_view;
545 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
546 g_return_if_fail (tree_column->button == NULL);
548 gtk_widget_push_composite_child ();
549 tree_column->button = gtk_button_new ();
550 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
551 gtk_widget_pop_composite_child ();
553 /* make sure we own a reference to it as well. */
554 if (tree_view->priv->header_window)
555 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
556 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
558 g_signal_connect (G_OBJECT (tree_column->button), "event",
559 G_CALLBACK (gtk_tree_view_column_button_event),
560 (gpointer) tree_column);
561 g_signal_connect (G_OBJECT (tree_column->button), "clicked",
562 (GtkSignalFunc) gtk_tree_view_column_button_clicked,
563 (gpointer) tree_column);
565 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
567 hbox = gtk_hbox_new (FALSE, 2);
568 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
570 if (tree_column->child)
571 child = tree_column->child;
574 child = gtk_label_new (tree_column->title);
575 gtk_widget_show (child);
578 g_signal_connect (G_OBJECT (child), "mnemonic_activate",
579 G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
580 (gpointer) tree_column);
582 if (tree_column->xalign <= 0.5)
583 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
585 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
587 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
589 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
590 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
592 gtk_widget_show (hbox);
593 gtk_widget_show (tree_column->alignment);
594 gtk_tree_view_column_update_button (tree_column);
598 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
601 GtkWidget *alignment;
603 GtkWidget *current_child;
605 /* Create a button if necessary */
606 if (tree_column->visible &&
607 tree_column->button == NULL &&
608 tree_column->tree_view &&
609 GTK_WIDGET_REALIZED (tree_column->tree_view))
610 gtk_tree_view_column_create_button (tree_column);
612 if (! tree_column->button)
615 hbox = GTK_BIN (tree_column->button)->child;
616 alignment = tree_column->alignment;
617 arrow = tree_column->arrow;
618 current_child = GTK_BIN (alignment)->child;
620 /* Set up the actual button */
621 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
624 if (tree_column->child)
626 if (current_child != tree_column->child)
628 gtk_container_remove (GTK_CONTAINER (alignment),
630 gtk_container_add (GTK_CONTAINER (alignment),
636 if (current_child == NULL)
638 current_child = gtk_label_new (NULL);
639 gtk_widget_show (current_child);
640 gtk_container_add (GTK_CONTAINER (alignment),
644 g_return_if_fail (GTK_IS_LABEL (current_child));
646 if (tree_column->title)
647 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
650 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
654 switch (tree_column->sort_order)
656 case GTK_SORT_ASCENDING:
657 gtk_arrow_set (GTK_ARROW (arrow),
662 case GTK_SORT_DESCENDING:
663 gtk_arrow_set (GTK_ARROW (arrow),
669 g_warning (G_STRLOC": bad sort order");
673 /* Put arrow on the right if the text is left-or-center justified, and on the
674 * left otherwise; do this by packing boxes, so flipping text direction will
677 gtk_widget_ref (arrow);
678 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
680 if (tree_column->xalign <= 0.5)
682 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
686 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
687 /* move it to the front */
688 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
690 gtk_widget_unref (arrow);
692 if (tree_column->show_sort_indicator)
693 gtk_widget_show (arrow);
695 gtk_widget_hide (arrow);
697 /* It's always safe to hide the button. It isn't always safe to show it, as
698 * if you show it before it's realized, it'll get the wrong window. */
699 if (tree_column->button &&
700 tree_column->tree_view != NULL &&
701 GTK_WIDGET_REALIZED (tree_column->tree_view))
703 if (tree_column->visible)
705 gtk_widget_show_now (tree_column->button);
706 if (tree_column->window)
708 if (tree_column->resizable)
710 gdk_window_show (tree_column->window);
711 gdk_window_raise (tree_column->window);
715 gdk_window_hide (tree_column->window);
721 gtk_widget_hide (tree_column->button);
722 if (tree_column->window)
723 gdk_window_hide (tree_column->window);
727 if (tree_column->reorderable || tree_column->clickable)
729 GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
733 GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
734 if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
736 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
737 if (GTK_WIDGET_TOPLEVEL (toplevel))
739 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
743 /* Queue a resize on the assumption that we always want to catch all changes
744 * and columns don't change all that often.
746 if (GTK_WIDGET_REALIZED (tree_column->tree_view))
747 gtk_widget_queue_resize (tree_column->tree_view);
751 /* Button signal handlers
755 gtk_tree_view_column_button_event (GtkWidget *widget,
759 GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
761 g_return_val_if_fail (event != NULL, FALSE);
763 if (event->type == GDK_BUTTON_PRESS &&
766 column->maybe_reordered = TRUE;
767 gdk_window_get_pointer (widget->window,
771 gtk_widget_grab_focus (widget);
774 if (event->type == GDK_BUTTON_RELEASE &&
775 column->maybe_reordered)
776 column->maybe_reordered = FALSE;
778 if (event->type == GDK_MOTION_NOTIFY &&
779 (column->maybe_reordered) &&
780 (gtk_drag_check_threshold (widget,
783 (gint) ((GdkEventMotion *)event)->x,
784 (gint) ((GdkEventMotion *)event)->y)))
786 column->maybe_reordered = FALSE;
787 /* this is to change our drag_x to be relative to
788 * tree_view->priv->bin_window, instead of our window.
790 column->drag_x -= column->button->allocation.x;
791 _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
794 if (column->clickable == FALSE)
798 case GDK_BUTTON_PRESS:
799 case GDK_2BUTTON_PRESS:
800 case GDK_3BUTTON_PRESS:
801 case GDK_MOTION_NOTIFY:
802 case GDK_BUTTON_RELEASE:
803 case GDK_ENTER_NOTIFY:
804 case GDK_LEAVE_NOTIFY:
815 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
817 g_signal_emit_by_name (G_OBJECT (data), "clicked");
821 gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
822 gboolean group_cycling,
825 GtkTreeViewColumn *column = (GtkTreeViewColumn *)data;
827 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE);
829 GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column;
830 if (column->clickable)
831 gtk_button_clicked (GTK_BUTTON (column->button));
832 else if (GTK_WIDGET_CAN_FOCUS (column->button))
833 gtk_widget_grab_focus (column->button);
835 gtk_widget_grab_focus (column->tree_view);
841 gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable,
842 GtkTreeViewColumn *column)
847 if (gtk_tree_sortable_get_sort_column_id (sortable,
851 if (sort_column_id == column->sort_column_id)
853 gtk_tree_view_column_set_sort_indicator (column, TRUE);
854 gtk_tree_view_column_set_sort_order (column, order);
858 gtk_tree_view_column_set_sort_indicator (column, FALSE);
863 gtk_tree_view_column_set_sort_indicator (column, FALSE);
868 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
873 gboolean has_sort_column;
874 gboolean has_default_sort_func;
876 g_return_if_fail (tree_column->tree_view != NULL);
879 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
882 has_default_sort_func =
883 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));
885 if (has_sort_column &&
886 sort_column_id == tree_column->sort_column_id)
888 if (order == GTK_SORT_ASCENDING)
889 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
890 tree_column->sort_column_id,
891 GTK_SORT_DESCENDING);
892 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
893 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
894 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
897 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
898 tree_column->sort_column_id,
903 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
904 tree_column->sort_column_id,
911 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
915 if (tree_column->tree_view == NULL)
918 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
923 if (GTK_IS_TREE_SORTABLE (model) &&
924 tree_column->sort_column_id != -1)
926 gint real_sort_column_id;
927 GtkSortType real_order;
929 if (tree_column->sort_column_changed_signal == 0)
930 tree_column->sort_column_changed_signal =
931 g_signal_connect (G_OBJECT (model), "sort_column_changed",
932 GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
935 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
936 &real_sort_column_id,
938 (real_sort_column_id == tree_column->sort_column_id))
940 gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
941 gtk_tree_view_column_set_sort_order (tree_column, real_order);
949 /* Exported Private Functions.
950 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
954 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
956 GtkTreeView *tree_view;
958 guint attributes_mask;
960 tree_view = (GtkTreeView *)column->tree_view;
962 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
963 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
964 g_return_if_fail (tree_view->priv->header_window != NULL);
965 g_return_if_fail (column->button != NULL);
967 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
970 gtk_widget_show (column->button);
972 attr.window_type = GDK_WINDOW_CHILD;
973 attr.wclass = GDK_INPUT_ONLY;
974 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
975 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
976 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
977 attr.event_mask = (GDK_BUTTON_PRESS_MASK |
978 GDK_BUTTON_RELEASE_MASK |
979 GDK_POINTER_MOTION_MASK |
980 GDK_POINTER_MOTION_HINT_MASK |
982 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
983 attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
984 GDK_SB_H_DOUBLE_ARROW);
986 attr.width = TREE_VIEW_DRAG_WIDTH;
987 attr.height = tree_view->priv->header_height;
989 attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
991 column->window = gdk_window_new (tree_view->priv->header_window,
992 &attr, attributes_mask);
993 gdk_window_set_user_data (column->window, tree_view);
995 gtk_tree_view_column_update_button (column);
997 gdk_cursor_unref (attr.cursor);
1001 _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
1003 g_return_if_fail (column != NULL);
1004 g_return_if_fail (column->window != NULL);
1006 gdk_window_set_user_data (column->window, NULL);
1007 gdk_window_destroy (column->window);
1008 column->window = NULL;
1012 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
1013 GtkTreeView *tree_view)
1015 g_assert (column->tree_view == NULL);
1017 column->tree_view = GTK_WIDGET (tree_view);
1018 gtk_tree_view_column_create_button (column);
1020 column->property_changed_signal =
1021 g_signal_connect_swapped (GTK_OBJECT (tree_view),
1023 GTK_SIGNAL_FUNC (gtk_tree_view_column_setup_sort_column_id_callback),
1026 gtk_tree_view_column_setup_sort_column_id_callback (column);
1030 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
1032 if (column->tree_view && column->button)
1034 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1036 if (column->property_changed_signal)
1038 g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
1039 column->property_changed_signal = 0;
1042 if (column->sort_column_changed_signal)
1044 g_signal_handler_disconnect (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view))),
1045 column->sort_column_changed_signal);
1046 column->sort_column_changed_signal = 0;
1049 column->tree_view = NULL;
1050 column->button = NULL;
1054 _gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
1058 for (list = column->cell_list; list; list = list->next)
1059 if (((GtkTreeViewColumnCellInfo *)list->data)->cell->mode ==
1060 GTK_CELL_RENDERER_MODE_EDITABLE)
1066 /* gets cell being edited */
1068 _gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column)
1072 for (list = column->cell_list; list; list = list->next)
1073 if (((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode)
1074 return ((GtkTreeViewColumnCellInfo *)list->data)->cell;
1080 _gtk_tree_view_column_count_special_cells (GtkTreeViewColumn *column)
1085 for (list = column->cell_list; list; list = list->next)
1087 GtkTreeViewColumnCellInfo *cellinfo = list->data;
1089 if (cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1090 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1098 _gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column,
1104 list = gtk_tree_view_column_cell_first (column);
1105 for (; list; list = gtk_tree_view_column_cell_next (column, list))
1107 GtkTreeViewColumnCellInfo *cellinfo = list->data;
1108 if (current_x <= x && x <= current_x + cellinfo->real_width)
1109 return cellinfo->cell;
1110 current_x += cellinfo->real_width;
1116 /* Public Functions */
1120 * gtk_tree_view_column_new:
1122 * Creates a new #GtkTreeViewColumn.
1124 * Return value: A newly created #GtkTreeViewColumn.
1127 gtk_tree_view_column_new (void)
1129 GtkTreeViewColumn *tree_column;
1131 tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
1137 * gtk_tree_view_column_new_with_attributes:
1138 * @title: The title to set the header to.
1139 * @cell: The #GtkCellRenderer.
1140 * @Varargs: A %NULL-terminated list of attributes.
1142 * Creates a new #GtkTreeViewColumn with a number of default values. This is
1143 * equivalent to calling gtk_tree_view_column_set_title(),
1144 * gtk_tree_view_column_pack_start(), and
1145 * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1147 * Here's a simple example:
1148 * <informalexample><programlisting>
1149 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1152 * GtkTreeViewColumn *column;
1153 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new (<!-- -->);
1155 * column = gtk_tree_view_column_new_with_attributes ("Title",
1157 * "text", TEXT_COLUMN,
1158 * "foreground", COLOR_COLUMN,
1161 * </programlisting></informalexample>
1163 * Return value: A newly created #GtkTreeViewColumn.
1166 gtk_tree_view_column_new_with_attributes (const gchar *title,
1167 GtkCellRenderer *cell,
1170 GtkTreeViewColumn *retval;
1173 retval = gtk_tree_view_column_new ();
1175 gtk_tree_view_column_set_title (retval, title);
1176 gtk_tree_view_column_pack_start (retval, cell, TRUE);
1178 va_start (args, cell);
1179 gtk_tree_view_column_set_attributesv (retval, cell, args);
1185 static GtkTreeViewColumnCellInfo *
1186 gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
1187 GtkCellRenderer *cell_renderer)
1190 for (list = tree_column->cell_list; list; list = list->next)
1191 if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
1192 return (GtkTreeViewColumnCellInfo *) list->data;
1198 * gtk_tree_view_column_pack_start:
1199 * @tree_column: A #GtkTreeViewColumn.
1200 * @cell: The #GtkCellRenderer.
1201 * @expand: %TRUE if @cell is to be given extra space allocated to box.
1203 * Packs the @cell into the beginning column. If @expand is %TRUE, then the
1204 * @cell is allocated a share of all available space that the @tree_column has.
1207 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1208 GtkCellRenderer *cell,
1211 GtkTreeViewColumnCellInfo *cell_info;
1213 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1214 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1215 g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1217 g_object_ref (G_OBJECT (cell));
1218 gtk_object_sink (GTK_OBJECT (cell));
1220 cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1221 cell_info->cell = cell;
1222 cell_info->expand = expand ? TRUE : FALSE;
1223 cell_info->pack = GTK_PACK_START;
1224 cell_info->has_focus = 0;
1225 cell_info->attributes = NULL;
1227 tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1231 * gtk_tree_view_column_pack_end:
1232 * @tree_column: A #GtkTreeViewColumn.
1233 * @cell: The #GtkCellRenderer.
1234 * @expand: %TRUE if @cell is to be given extra space allocated to box.
1236 * Packs the @cell into the column. If @expand is %TRUE, then the @cell is
1237 * allocated a share of all available space that the @tree_column has.
1240 gtk_tree_view_column_pack_end (GtkTreeViewColumn *tree_column,
1241 GtkCellRenderer *cell,
1244 GtkTreeViewColumnCellInfo *cell_info;
1246 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1247 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1248 g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1250 g_object_ref (G_OBJECT (cell));
1251 gtk_object_sink (GTK_OBJECT (cell));
1253 cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1254 cell_info->cell = cell;
1255 cell_info->expand = expand ? TRUE : FALSE;
1256 cell_info->pack = GTK_PACK_END;
1257 cell_info->has_focus = 0;
1258 cell_info->attributes = NULL;
1260 tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1265 * gtk_tree_view_column_clear:
1266 * @tree_column: A #GtkTreeViewColumn
1268 * Unsets all the mappings on all renderers on the @tree_column.
1271 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1274 g_return_if_fail (tree_column != NULL);
1276 for (list = tree_column->cell_list; list; list = list->next)
1278 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1280 gtk_tree_view_column_clear_attributes (tree_column, info->cell);
1281 g_object_unref (G_OBJECT (info->cell));
1285 g_list_free (tree_column->cell_list);
1286 tree_column->cell_list = NULL;
1290 * gtk_tree_view_column_get_cell_renderers:
1291 * @tree_column: A #GtkTreeViewColumn
1293 * Returns a newly-allocated #GList of all the cell renderers in the column,
1294 * in no particular order. The list must be freed with g_list_free().
1296 * Return value: A list of #GtkCellRenderers
1299 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
1301 GList *retval = NULL, *list;
1303 g_return_val_if_fail (tree_column != NULL, NULL);
1305 for (list = tree_column->cell_list; list; list = list->next)
1307 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1309 retval = g_list_append (retval, info->cell);
1316 * gtk_tree_view_column_add_attribute:
1317 * @tree_column: A #GtkTreeViewColumn.
1318 * @cell_renderer: the #GtkCellRenderer to set attributes on
1319 * @attribute: An attribute on the renderer
1320 * @column: The column position on the model to get the attribute from.
1322 * Adds an attribute mapping to the list in @tree_column. The @column is the
1323 * column of the model to get a value from, and the @attribute is the
1324 * parameter on @cell_renderer to be set from the value. So for example
1325 * if column 2 of the model contains strings, you could have the
1326 * "text" attribute of a #GtkCellRendererText get its values from
1330 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1331 GtkCellRenderer *cell_renderer,
1332 const gchar *attribute,
1335 GtkTreeViewColumnCellInfo *info;
1337 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1338 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1339 g_return_if_fail (info != NULL);
1341 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
1342 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
1344 if (tree_column->tree_view)
1345 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1350 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1351 GtkCellRenderer *cell_renderer,
1357 attribute = va_arg (args, gchar *);
1359 gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1361 while (attribute != NULL)
1363 column = va_arg (args, gint);
1364 gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1365 attribute = va_arg (args, gchar *);
1370 * gtk_tree_view_column_set_attributes:
1371 * @tree_column: A #GtkTreeViewColumn.
1372 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1373 * @Varargs: A %NULL-terminated list of attributes.
1375 * Sets the attributes in the list as the attributes of @tree_column.
1376 * The attributes should be in attribute/column order, as in
1377 * gtk_tree_view_column_add_attribute(). All existing attributes
1378 * are removed, and replaced with the new attributes.
1381 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1382 GtkCellRenderer *cell_renderer,
1387 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1388 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1389 g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer));
1391 va_start (args, cell_renderer);
1392 gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1398 * gtk_tree_view_column_set_cell_data_func:
1399 * @tree_column: A #GtkTreeViewColumn
1400 * @cell_renderer: A #GtkCellRenderer
1401 * @func: The #GtkTreeViewColumnFunc to use.
1402 * @func_data: The user data for @func.
1403 * @destroy: The destroy notification for @func_data
1405 * Sets the #GtkTreeViewColumnFunc to use for the column. This
1406 * function is used instead of the standard attributes mapping for
1407 * setting the column value, and should set the value of @tree_column's
1408 * cell renderer as appropriate. @func may be %NULL to remove an
1412 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn *tree_column,
1413 GtkCellRenderer *cell_renderer,
1414 GtkTreeCellDataFunc func,
1416 GtkDestroyNotify destroy)
1418 GtkTreeViewColumnCellInfo *info;
1420 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1421 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1422 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1424 g_return_if_fail (info != NULL);
1428 GtkDestroyNotify d = info->destroy;
1430 info->destroy = NULL;
1431 d (info->func_data);
1435 info->func_data = func_data;
1436 info->destroy = destroy;
1438 if (tree_column->tree_view)
1439 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1444 * gtk_tree_view_column_clear_attributes:
1445 * @tree_column: a #GtkTreeViewColumn
1446 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1448 * Clears all existing attributes previously set with
1449 * gtk_tree_view_column_set_attributes().
1452 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1453 GtkCellRenderer *cell_renderer)
1455 GtkTreeViewColumnCellInfo *info;
1457 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1458 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1460 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1462 gtk_tree_view_column_clear_attributes_by_info (tree_column, info);
1466 gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
1467 GtkTreeViewColumnCellInfo *info)
1471 list = info->attributes;
1473 while (list && list->next)
1475 g_free (list->data);
1476 list = list->next->next;
1478 g_slist_free (info->attributes);
1479 info->attributes = NULL;
1481 if (tree_column->tree_view)
1482 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1487 * gtk_tree_view_column_set_spacing:
1488 * @tree_column: A #GtkTreeViewColumn.
1489 * @spacing: distance between cell renderers in pixels.
1491 * Sets the spacing field of @tree_column, which is the number of pixels to
1492 * place between cell renderers packed into it.
1495 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1498 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1499 g_return_if_fail (spacing >= 0);
1501 if (tree_column->spacing == spacing)
1504 tree_column->spacing = spacing;
1505 if (tree_column->tree_view)
1506 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1510 * gtk_tree_view_column_get_spacing:
1511 * @tree_column: A #GtkTreeViewColumn.
1513 * Returns the spacing of @tree_column.
1515 * Return value: the spacing of @tree_column.
1518 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1520 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1522 return tree_column->spacing;
1525 /* Options for manipulating the columns */
1528 * gtk_tree_view_column_set_visible:
1529 * @tree_column: A #GtkTreeViewColumn.
1530 * @visible: %TRUE if the @tree_column is visible.
1532 * Sets the visibility of @tree_column.
1535 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1538 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1540 visible = !! visible;
1542 if (tree_column->visible == visible)
1545 tree_column->visible = visible;
1547 if (tree_column->visible)
1548 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1550 gtk_tree_view_column_update_button (tree_column);
1551 g_object_notify (G_OBJECT (tree_column), "visible");
1555 * gtk_tree_view_column_get_visible:
1556 * @tree_column: A #GtkTreeViewColumn.
1558 * Returns %TRUE if @tree_column is visible.
1560 * Return value: whether the column is visible or not. If it is visible, then
1561 * the tree will show the column.
1564 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1566 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1568 return tree_column->visible;
1572 * gtk_tree_view_column_set_resizable:
1573 * @tree_column: A #GtkTreeViewColumn
1574 * @resizable: %TRUE, if the column can be resized
1576 * If @resizable is %TRUE, then the user can explicitly resize the column by
1577 * grabbing the outer edge of the column button. If resizable is TRUE and
1578 * sizing mode of the column is #GTK_TREE_VIEW_COLUMN_AUTOSIZE, then the sizing
1579 * mode is changed to #GTK_TREE_VIEW_COLUMN_GROW_ONLY.
1582 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1585 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1587 resizable = !! resizable;
1589 if (tree_column->resizable == resizable)
1592 tree_column->resizable = resizable;
1594 if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1595 gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1597 gtk_tree_view_column_update_button (tree_column);
1599 g_object_notify (G_OBJECT (tree_column), "resizable");
1603 * gtk_tree_view_column_get_resizable:
1604 * @tree_column: A #GtkTreeViewColumn
1606 * Returns #TRUE if the @tree_column can be resized by the end user.
1608 * Return value: #TRUE, if the @tree_column can be resized.
1611 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1613 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1615 return tree_column->resizable;
1620 * gtk_tree_view_column_set_sizing:
1621 * @tree_column: A #GtkTreeViewColumn.
1622 * @type: The #GtkTreeViewColumnSizing.
1624 * Sets the growth behavior of @tree_column to @type.
1627 gtk_tree_view_column_set_sizing (GtkTreeViewColumn *tree_column,
1628 GtkTreeViewColumnSizing type)
1630 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1632 if (type == tree_column->column_type)
1635 if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1636 gtk_tree_view_column_set_resizable (tree_column, FALSE);
1639 /* I was clearly on crack when I wrote this. I'm not sure what's supposed to
1640 * be below so I'll leave it until I figure it out.
1642 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
1643 tree_column->requested_width != -1)
1645 gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
1648 tree_column->column_type = type;
1650 gtk_tree_view_column_update_button (tree_column);
1652 g_object_notify (G_OBJECT (tree_column), "sizing");
1656 * gtk_tree_view_column_get_sizing:
1657 * @tree_column: A #GtkTreeViewColumn.
1659 * Returns the current type of @tree_column.
1661 * Return value: The type of @tree_column.
1663 GtkTreeViewColumnSizing
1664 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1666 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1668 return tree_column->column_type;
1672 * gtk_tree_view_column_get_width:
1673 * @tree_column: A #GtkTreeViewColumn.
1675 * Returns the current size of @tree_column in pixels.
1677 * Return value: The current width of @tree_column.
1680 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1682 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1684 return tree_column->width;
1688 * gtk_tree_view_column_set_fixed_width:
1689 * @tree_column: A #GtkTreeViewColumn.
1690 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1692 * Sets the size of the column in pixels. This is meaningful only if the sizing
1693 * type is #GTK_TREE_VIEW_COLUMN_FIXED. The size of the column is clamped to
1694 * the min/max width for the column. Please note that the min/max width of the
1695 * column doesn't actually affect the "fixed_width" property of the widget, just
1696 * the actual size when displayed.
1699 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
1702 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1703 g_return_if_fail (fixed_width > 0);
1705 tree_column->fixed_width = fixed_width;
1707 if (tree_column->tree_view &&
1708 GTK_WIDGET_REALIZED (tree_column->tree_view) &&
1709 tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1711 gtk_widget_queue_resize (tree_column->tree_view);
1714 g_object_notify (G_OBJECT (tree_column), "fixed_width");
1718 * gtk_tree_view_column_get_fixed_width:
1719 * @tree_column: a #GtkTreeViewColumn
1721 * Gets the fixed width of the column. This value is only meaning may not be
1722 * the actual width of the column on the screen, just what is requested.
1724 * Return value: the fixed width of the column
1727 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
1729 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1731 return tree_column->fixed_width;
1735 * gtk_tree_view_column_set_min_width:
1736 * @tree_column: A #GtkTreeViewColumn.
1737 * @min_width: The minimum width of the column in pixels, or -1.
1739 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
1740 * minimum width is unset.
1743 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
1746 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1747 g_return_if_fail (min_width >= -1);
1749 if (min_width == tree_column->min_width)
1752 if (tree_column->visible &&
1753 tree_column->tree_view != NULL &&
1754 GTK_WIDGET_REALIZED (tree_column->tree_view))
1756 if (min_width > tree_column->width)
1757 gtk_widget_queue_resize (tree_column->tree_view);
1760 tree_column->min_width = min_width;
1761 g_object_freeze_notify (G_OBJECT (tree_column));
1762 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1764 tree_column->max_width = min_width;
1765 g_object_notify (G_OBJECT (tree_column), "max_width");
1767 g_object_notify (G_OBJECT (tree_column), "min_width");
1768 g_object_thaw_notify (G_OBJECT (tree_column));
1770 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1771 _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1776 * gtk_tree_view_column_get_min_width:
1777 * @tree_column: A #GtkTreeViewColumn.
1779 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1782 * Return value: The minimum width of the @tree_column.
1785 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
1787 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1789 return tree_column->min_width;
1793 * gtk_tree_view_column_set_max_width:
1794 * @tree_column: A #GtkTreeViewColumn.
1795 * @max_width: The maximum width of the column in pixels, or -1.
1797 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
1798 * maximum width is unset. Note, the column can actually be wider than max
1799 * width if it's the last column in a view. In this case, the column expands to
1800 * fill any extra space.
1803 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
1806 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1807 g_return_if_fail (max_width >= -1);
1809 if (max_width == tree_column->max_width)
1812 if (tree_column->visible &&
1813 tree_column->tree_view != NULL &&
1814 GTK_WIDGET_REALIZED (tree_column->tree_view))
1816 if (max_width != -1 && max_width < tree_column->width)
1817 gtk_widget_queue_resize (tree_column->tree_view);
1820 tree_column->max_width = max_width;
1821 g_object_freeze_notify (G_OBJECT (tree_column));
1822 if (max_width != -1 && max_width < tree_column->min_width)
1824 tree_column->min_width = max_width;
1825 g_object_notify (G_OBJECT (tree_column), "min_width");
1827 g_object_notify (G_OBJECT (tree_column), "max_width");
1828 g_object_thaw_notify (G_OBJECT (tree_column));
1830 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1831 _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1836 * gtk_tree_view_column_get_max_width:
1837 * @tree_column: A #GtkTreeViewColumn.
1839 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
1842 * Return value: The maximum width of the @tree_column.
1845 gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
1847 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1849 return tree_column->max_width;
1853 * gtk_tree_view_column_clicked:
1854 * @tree_column: a #GtkTreeViewColumn
1856 * Emits the "clicked" signal on the column. This function will only work if
1857 * @tree_column is clickable.
1860 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
1862 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1864 if (tree_column->visible &&
1865 tree_column->button &&
1866 tree_column->clickable)
1867 gtk_button_clicked (GTK_BUTTON (tree_column->button));
1871 * gtk_tree_view_column_set_title:
1872 * @tree_column: A #GtkTreeViewColumn.
1873 * @title: The title of the @tree_column.
1875 * Sets the title of the @tree_column. If a custom widget has been set, then
1876 * this value is ignored.
1879 gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
1882 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1884 g_free (tree_column->title);
1886 tree_column->title = g_strdup (title);
1888 tree_column->title = NULL;
1890 gtk_tree_view_column_update_button (tree_column);
1891 g_object_notify (G_OBJECT (tree_column), "title");
1895 * gtk_tree_view_column_get_title:
1896 * @tree_column: A #GtkTreeViewColumn.
1898 * Returns the title of the widget. This value should not be modified.
1900 * Return value: the title of the column.
1902 G_CONST_RETURN gchar *
1903 gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
1905 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1907 return tree_column->title;
1911 * gtk_tree_view_column_set_clickable:
1912 * @tree_column: A #GtkTreeViewColumn.
1913 * @clickable: %TRUE if the header is active.
1915 * Sets the header to be active if @active is %TRUE. When the header is active,
1916 * then it can take keyboard focus, and can be clicked.
1919 gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
1922 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1924 clickable = !! clickable;
1925 if (tree_column->clickable == clickable)
1928 tree_column->clickable = clickable;
1929 gtk_tree_view_column_update_button (tree_column);
1930 g_object_notify (G_OBJECT (tree_column), "clickable");
1934 * gtk_tree_view_column_get_clickable:
1935 * @tree_column: a #GtkTreeViewColumn
1937 * Returns %TRUE if the user can click on the header for the column.
1939 * Return value: %TRUE if user can click the column header.
1942 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
1944 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1946 return tree_column->clickable;
1950 * gtk_tree_view_column_set_widget:
1951 * @tree_column: A #GtkTreeViewColumn.
1952 * @widget: A child #GtkWidget, or %NULL.
1954 * Sets the widget in the header to be @widget. If widget is %NULL, then the
1955 * header button is set with a #GtkLabel set to the title of @tree_column.
1958 gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
1961 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1962 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
1966 gtk_object_ref (GTK_OBJECT (widget));
1967 gtk_object_sink (GTK_OBJECT (widget));
1970 if (tree_column->child)
1971 gtk_object_unref (GTK_OBJECT (tree_column->child));
1973 tree_column->child = widget;
1974 gtk_tree_view_column_update_button (tree_column);
1975 g_object_notify (G_OBJECT (tree_column), "widget");
1979 * gtk_tree_view_column_get_widget:
1980 * @tree_column: A #GtkTreeViewColumn.
1982 * Returns the #GtkWidget in the button on the column header. If a custom
1983 * widget has not been set then %NULL is returned.
1985 * Return value: The #GtkWidget in the column header, or %NULL
1988 gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
1990 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1992 return tree_column->child;
1996 * gtk_tree_view_column_set_alignment:
1997 * @tree_column: A #GtkTreeViewColumn.
1998 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
2000 * Sets the alignment of the title or custom widget inside the column header.
2001 * The alignment determines its location inside the button -- 0.0 for left, 0.5
2002 * for center, 1.0 for right.
2005 gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
2008 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2010 xalign = CLAMP (xalign, 0.0, 1.0);
2012 if (tree_column->xalign == xalign)
2015 tree_column->xalign = xalign;
2016 gtk_tree_view_column_update_button (tree_column);
2017 g_object_notify (G_OBJECT (tree_column), "alignment");
2021 * gtk_tree_view_column_get_alignment:
2022 * @tree_column: A #GtkTreeViewColumn.
2024 * Returns the current x alignment of @tree_column. This value can range
2025 * between 0.0 and 1.0.
2027 * Return value: The current alignent of @tree_column.
2030 gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
2032 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5);
2034 return tree_column->xalign;
2038 * gtk_tree_view_column_set_reorderable:
2039 * @tree_column: A #GtkTreeViewColumn
2040 * @reorderable: #TRUE, if the column can be reordered.
2042 * If @reorderable is #TRUE, then the column can be reordered by the end user
2043 * dragging the header.
2046 gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
2047 gboolean reorderable)
2049 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2052 gtk_tree_view_column_set_clickable (tree_column, TRUE);*/
2054 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2057 tree_column->reorderable = (reorderable?TRUE:FALSE);
2058 gtk_tree_view_column_update_button (tree_column);
2059 g_object_notify (G_OBJECT (tree_column), "reorderable");
2063 * gtk_tree_view_column_get_reorderable:
2064 * @tree_column: A #GtkTreeViewColumn
2066 * Returns #TRUE if the @tree_column can be reordered by the user.
2068 * Return value: #TRUE if the @tree_column can be reordered by the user.
2071 gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
2073 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2075 return tree_column->reorderable;
2080 * gtk_tree_view_column_set_sort_column_id:
2081 * @tree_column: a #GtkTreeViewColumn
2082 * @sort_column_id: The @sort_column_id of the model to sort on.
2084 * Sets the logical @sort_column_id that this column sorts on when this column
2085 * is selected for sorting. Doing so makes the column header clickable.
2088 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
2089 gint sort_column_id)
2091 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2092 g_return_if_fail (sort_column_id >= 0);
2094 if (tree_column->sort_column_id == sort_column_id)
2097 tree_column->sort_column_id = sort_column_id;
2099 /* Handle unsetting the id */
2100 if (sort_column_id == -1)
2102 if (tree_column->sort_clicked_signal)
2104 g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
2105 tree_column->sort_clicked_signal = 0;
2108 if (tree_column->sort_column_changed_signal)
2110 g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
2111 tree_column->sort_column_changed_signal = 0;
2114 gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2115 gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
2119 gtk_tree_view_column_set_clickable (tree_column, TRUE);
2121 if (! tree_column->sort_clicked_signal)
2122 tree_column->sort_clicked_signal = g_signal_connect (G_OBJECT (tree_column),
2124 G_CALLBACK (gtk_tree_view_column_sort),
2127 gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
2131 * gtk_tree_view_column_get_sort_column_id:
2132 * @tree_column: a #GtkTreeViewColumn
2134 * Gets the logical @sort_column_id that the model sorts on when this
2135 * column is selected for sorting. See gtk_tree_view_column_set_sort_column_id().
2137 * Return value: the current @sort_column_id for this column, or -1 if
2138 * this column can't be used for sorting.
2141 gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column)
2143 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2145 return tree_column->sort_column_id;
2149 * gtk_tree_view_column_set_sort_indicator:
2150 * @tree_column: a #GtkTreeViewColumn
2151 * @setting: %TRUE to display an indicator that the column is sorted
2153 * Call this function with a @setting of %TRUE to display an arrow in
2154 * the header button indicating the column is sorted. Call
2155 * gtk_tree_view_column_set_sort_order() to change the direction of
2160 gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn *tree_column,
2163 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2165 setting = setting != FALSE;
2167 if (setting == tree_column->show_sort_indicator)
2170 tree_column->show_sort_indicator = setting;
2171 gtk_tree_view_column_update_button (tree_column);
2172 g_object_notify (G_OBJECT (tree_column), "sort_indicator");
2176 * gtk_tree_view_column_get_sort_indicator:
2177 * @tree_column: a #GtkTreeViewColumn
2179 * Gets the value set by gtk_tree_view_column_set_sort_indicator().
2181 * Return value: whether the sort indicator arrow is displayed
2184 gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column)
2186 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2188 return tree_column->show_sort_indicator;
2192 * gtk_tree_view_column_set_sort_order:
2193 * @tree_column: a #GtkTreeViewColumn
2194 * @order: sort order that the sort indicator should indicate
2196 * Changes the appearance of the sort indicator.
2198 * This <emphasis>does not</emphasis> actually sort the model. Use
2199 * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
2200 * support. This function is primarily for custom sorting behavior, and should
2201 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2202 * that. For custom models, the mechanism will vary.
2204 * The sort indicator changes direction to indicate normal sort or reverse sort.
2205 * Note that you must have the sort indicator enabled to see anything when
2206 * calling this function; see gtk_tree_view_column_set_sort_indicator().
2209 gtk_tree_view_column_set_sort_order (GtkTreeViewColumn *tree_column,
2212 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2214 if (order == tree_column->sort_order)
2217 tree_column->sort_order = order;
2218 gtk_tree_view_column_update_button (tree_column);
2219 g_object_notify (G_OBJECT (tree_column), "sort_order");
2223 * gtk_tree_view_column_get_sort_order:
2224 * @tree_column: a #GtkTreeViewColumn
2226 * Gets the value set by gtk_tree_view_column_set_sort_order().
2228 * Return value: the sort order the sort indicator is indicating
2231 gtk_tree_view_column_get_sort_order (GtkTreeViewColumn *tree_column)
2233 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2235 return tree_column->sort_order;
2239 * gtk_tree_view_column_cell_set_cell_data:
2240 * @tree_column: A #GtkTreeViewColumn.
2241 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2242 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2243 * @is_expander: %TRUE, if the row has children
2244 * @is_expanded: %TRUE, if the row has visible children
2246 * Sets the cell renderer based on the @tree_model and @tree_node. That is, for
2247 * every attribute mapping in @tree_column, it will get a value from the set
2248 * column on the @tree_node, and use that value to set the attribute on the cell
2249 * renderer. This is used primarily by the #GtkTreeView.
2252 gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
2253 GtkTreeModel *tree_model,
2255 gboolean is_expander,
2256 gboolean is_expanded)
2259 GValue value = { 0, };
2262 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2263 g_return_if_fail (tree_column->cell_list != NULL);
2265 if (tree_model == NULL)
2268 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2270 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
2271 GObject *cell = (GObject *) info->cell;
2273 list = info->attributes;
2275 g_object_freeze_notify (cell);
2276 g_object_set (cell, "is_expander", is_expander, "is_expanded", is_expanded, NULL);
2278 while (list && list->next)
2280 gtk_tree_model_get_value (tree_model, iter,
2281 GPOINTER_TO_INT (list->next->data),
2283 g_object_set_property (cell, (gchar *) list->data, &value);
2284 g_value_unset (&value);
2285 list = list->next->next;
2289 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2290 g_object_thaw_notify (G_OBJECT (info->cell));
2296 * gtk_tree_view_column_cell_get_size:
2297 * @tree_column: A #GtkTreeViewColumn.
2298 * @cell_area: The area a cell in the column will be allocated, or %NULL
2299 * @x_offset: location to return x offset of a cell relative to @cell_area, or %NULL
2300 * @y_offset: location to return y offset of a cell relative to @cell_area, or %NULL
2301 * @width: location to return width needed to render a cell, or %NULL
2302 * @height: location to return height needed to render a cell, or %NULL
2304 * Obtains the width and height needed to render the column. This is used
2305 * primarily by the #GtkTreeView.
2308 gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
2309 GdkRectangle *cell_area,
2316 gboolean first_cell = TRUE;
2317 gint focus_line_width;
2319 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2326 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2328 for (list = tree_column->cell_list; list; list = list->next)
2330 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2332 gint new_height = 0;
2334 g_object_get (info->cell, "visible", &visible, NULL);
2336 if (visible == FALSE)
2339 if (first_cell == FALSE && *width)
2340 *width += tree_column->spacing;
2342 gtk_cell_renderer_get_size (info->cell,
2343 tree_column->tree_view,
2351 * height = MAX (*height, new_height + focus_line_width * 2);
2352 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2354 * width += info->requested_width;
2359 /* both rendering and rendering focus are somewhat complicated, and a bit of
2360 * code. Rather than duplicate them, we put them together to keep the code in
2370 gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column,
2372 GdkRectangle *background_area,
2373 GdkRectangle *cell_area,
2376 GdkRectangle *expose_area, /* RENDER */
2377 GdkRectangle *focus_rectangle, /* FOCUS */
2378 GtkCellEditable **editable_widget, /* EVENT */
2379 GdkEvent *event, /* EVENT */
2380 gchar *path_string) /* EVENT */
2383 GdkRectangle real_cell_area;
2384 GdkRectangle real_background_area;
2385 gint expand_cell_count = 0;
2386 gint full_requested_width = 0;
2388 gint min_x, min_y, max_x, max_y;
2389 gint focus_line_width;
2398 special_cells = _gtk_tree_view_column_count_special_cells (tree_column);
2400 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2402 GtkTreeViewColumnCellInfo *info = NULL;
2403 gboolean found_has_focus = FALSE;
2405 /* one should have focus */
2406 for (list = tree_column->cell_list; list; list = list->next)
2409 if (info && info->has_focus)
2411 found_has_focus = TRUE;
2416 if (!found_has_focus)
2418 /* give the first one focus */
2419 info = gtk_tree_view_column_cell_first (tree_column)->data;
2420 info->has_focus = TRUE;
2424 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2425 "focus-line-width", &focus_line_width,
2428 real_cell_area = *cell_area;
2429 real_background_area = *background_area;
2430 dx = real_cell_area.x - real_background_area.x - focus_line_width;
2432 real_cell_area.x += focus_line_width;
2434 /* Find out how many extra space we have to allocate */
2435 for (list = tree_column->cell_list; list; list = list->next)
2437 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
2439 if (! info->cell->visible)
2442 if (info->expand == TRUE)
2443 expand_cell_count ++;
2444 full_requested_width += info->requested_width;
2447 extra_space = background_area->width - full_requested_width;
2448 if (extra_space < 0)
2450 else if (extra_space > 0 && expand_cell_count > 0)
2451 extra_space /= expand_cell_count;
2453 /* iterate list for GTK_PACK_START cells */
2454 for (list = tree_column->cell_list; list; list = list->next)
2456 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2458 if (info->pack == GTK_PACK_END)
2461 if (! info->cell->visible)
2464 real_background_area.width = info->requested_width +
2465 (info->expand?extra_space:0);
2466 info->real_width = real_background_area.width;
2468 real_cell_area.width = real_background_area.width;
2469 real_cell_area.width -= 2 * focus_line_width;
2471 if (action == CELL_ACTION_RENDER)
2473 gtk_cell_renderer_render (info->cell,
2475 tree_column->tree_view,
2476 &real_background_area,
2481 else if (action == CELL_ACTION_FOCUS)
2483 gint x_offset, y_offset, width, height;
2485 gtk_cell_renderer_get_size (info->cell,
2486 tree_column->tree_view,
2488 &x_offset, &y_offset,
2491 if (special_cells > 1)
2493 if (info->has_focus)
2495 min_x = real_cell_area.x + x_offset;
2496 max_x = min_x + width;
2497 min_y = real_cell_area.y + y_offset;
2498 max_y = min_y + height;
2503 if (min_x > (real_cell_area.x + x_offset))
2504 min_x = real_cell_area.x + x_offset;
2505 if (max_x < real_cell_area.x + x_offset + width)
2506 max_x = real_cell_area.x + x_offset + width;
2507 if (min_y > (real_cell_area.y + y_offset))
2508 min_y = real_cell_area.y + y_offset;
2509 if (max_y < real_cell_area.y + y_offset + height)
2510 max_y = real_cell_area.y + y_offset + height;
2513 else if (action == CELL_ACTION_EVENT)
2515 gboolean try_event = FALSE;
2519 if (special_cells == 1)
2521 /* only 1 activatable cell -> whole column can activate */
2522 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2523 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2526 else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2527 real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2528 /* only activate cell if the user clicked on an individual
2533 else if (special_cells > 1 && info->has_focus)
2535 else if (special_cells == 1)
2540 gboolean visible, mode;
2542 g_object_get (G_OBJECT (info->cell),
2543 "visible", &visible,
2546 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2548 if (gtk_cell_renderer_activate (info->cell,
2550 tree_column->tree_view,
2557 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2560 gtk_cell_renderer_start_editing (info->cell,
2562 tree_column->tree_view,
2568 if (*editable_widget != NULL)
2570 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2571 info->in_editing_mode = TRUE;
2572 gtk_tree_view_column_focus_cell (tree_column, info->cell);
2580 real_cell_area.x += (info->real_width + tree_column->spacing);
2581 real_background_area.x += (info->real_width + tree_column->spacing);
2584 /* iterate list for PACK_END cells */
2585 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2587 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2589 if (info->pack == GTK_PACK_START)
2592 if (! info->cell->visible)
2595 real_background_area.width = info->requested_width +
2596 (info->expand?extra_space:0);
2597 info->real_width = real_background_area.width;
2599 real_cell_area.width = real_background_area.width;
2600 real_cell_area.width -= 2 * focus_line_width;
2602 if (action == CELL_ACTION_RENDER)
2604 gtk_cell_renderer_render (info->cell,
2606 tree_column->tree_view,
2607 &real_background_area,
2612 else if (action == CELL_ACTION_FOCUS)
2614 gint x_offset, y_offset, width, height;
2616 gtk_cell_renderer_get_size (info->cell,
2617 tree_column->tree_view,
2619 &x_offset, &y_offset,
2622 if (special_cells > 1)
2624 if (info->has_focus)
2626 min_x = real_cell_area.x + x_offset;
2627 max_x = min_x + width;
2628 min_y = real_cell_area.y + y_offset;
2629 max_y = min_y + height;
2634 if (min_x > (real_cell_area.x + x_offset))
2635 min_x = real_cell_area.x + x_offset;
2636 if (max_x < real_cell_area.x + x_offset + width)
2637 max_x = real_cell_area.x + x_offset + width;
2638 if (min_y > (real_cell_area.y + y_offset))
2639 min_y = real_cell_area.y + y_offset;
2640 if (max_y < real_cell_area.y + y_offset + height)
2641 max_y = real_cell_area.y + y_offset + height;
2644 else if (action == CELL_ACTION_EVENT)
2646 gboolean try_event = FALSE;
2650 if (special_cells == 1)
2652 /* only 1 activatable cell -> whole column can activate */
2653 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2654 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2657 else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2658 real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2659 /* only activate cell if the user clicked on an individual
2664 else if (special_cells > 1 && info->has_focus)
2666 else if (special_cells == 1)
2671 gboolean visible, mode;
2673 g_object_get (G_OBJECT (info->cell),
2674 "visible", &visible,
2677 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2679 if (gtk_cell_renderer_activate (info->cell,
2681 tree_column->tree_view,
2688 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2691 gtk_cell_renderer_start_editing (info->cell,
2693 tree_column->tree_view,
2699 if (*editable_widget != NULL)
2701 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2702 info->in_editing_mode = TRUE;
2703 gtk_tree_view_column_focus_cell (tree_column, info->cell);
2711 real_cell_area.x += (info->real_width + tree_column->spacing);
2712 real_background_area.x += (info->real_width + tree_column->spacing);
2715 /* fill focus_rectangle when required */
2716 if (action == CELL_ACTION_FOCUS)
2718 if (min_x >= max_x || min_y >= max_y)
2720 *focus_rectangle = *cell_area;
2721 /* don't change the focus_rectangle, just draw it nicely inside
2726 focus_rectangle->x = min_x - focus_line_width;
2727 focus_rectangle->y = min_y - focus_line_width;
2728 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
2729 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
2737 * gtk_tree_view_column_cell_render:
2738 * @tree_column: A #GtkTreeViewColumn.
2739 * @window: a #GdkDrawable to draw to
2740 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2741 * @cell_area: area normally rendered by a cell renderer
2742 * @expose_area: area that actually needs updating
2743 * @flags: flags that affect rendering
2745 * Renders the cell contained by #tree_column. This is used primarily by the
2749 _gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
2751 GdkRectangle *background_area,
2752 GdkRectangle *cell_area,
2753 GdkRectangle *expose_area,
2756 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2757 g_return_if_fail (background_area != NULL);
2758 g_return_if_fail (cell_area != NULL);
2759 g_return_if_fail (expose_area != NULL);
2761 gtk_tree_view_column_cell_process_action (tree_column,
2768 NULL, NULL, NULL, NULL);
2772 _gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column,
2773 GtkCellEditable **editable_widget,
2776 GdkRectangle *background_area,
2777 GdkRectangle *cell_area,
2780 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2782 return gtk_tree_view_column_cell_process_action (tree_column,
2794 /* cell list manipulation */
2796 gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column)
2798 GList *list = tree_column->cell_list;
2800 /* first GTK_PACK_START cell we find */
2801 for ( ; list; list = list->next)
2803 GtkTreeViewColumnCellInfo *info = list->data;
2804 if (info->pack == GTK_PACK_START)
2808 /* hmm, else the *last* GTK_PACK_END cell */
2809 list = g_list_last (tree_column->cell_list);
2811 for ( ; list; list = list->prev)
2813 GtkTreeViewColumnCellInfo *info = list->data;
2814 if (info->pack == GTK_PACK_END)
2822 gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column)
2824 GList *list = tree_column->cell_list;
2826 /* *first* GTK_PACK_END cell we find */
2827 for ( ; list ; list = list->next)
2829 GtkTreeViewColumnCellInfo *info = list->data;
2830 if (info->pack == GTK_PACK_END)
2834 /* hmm, else the last GTK_PACK_START cell */
2835 list = g_list_last (tree_column->cell_list);
2837 for ( ; list; list = list->prev)
2839 GtkTreeViewColumnCellInfo *info = list->data;
2840 if (info->pack == GTK_PACK_START)
2848 gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column,
2852 GtkTreeViewColumnCellInfo *info = current->data;
2854 if (info->pack == GTK_PACK_START)
2856 for (list = current->next; list; list = list->next)
2858 GtkTreeViewColumnCellInfo *inf = list->data;
2859 if (inf->pack == GTK_PACK_START)
2863 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
2864 list = g_list_last (tree_column->cell_list);
2865 for (; list; list = list->prev)
2867 GtkTreeViewColumnCellInfo *inf = list->data;
2868 if (inf->pack == GTK_PACK_END)
2873 for (list = current->prev; list; list = list->prev)
2875 GtkTreeViewColumnCellInfo *inf = list->data;
2876 if (inf->pack == GTK_PACK_END)
2884 gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column,
2888 GtkTreeViewColumnCellInfo *info = current->data;
2890 if (info->pack == GTK_PACK_END)
2892 for (list = current->next; list; list = list->next)
2894 GtkTreeViewColumnCellInfo *inf = list->data;
2895 if (inf->pack == GTK_PACK_END)
2899 /* out of GTK_PACK_END, get last GTK_PACK_START one */
2900 list = g_list_last (tree_column->cell_list);
2901 for ( ; list; list = list->prev)
2903 GtkTreeViewColumnCellInfo *inf = list->data;
2904 if (inf->pack == GTK_PACK_START)
2909 for (list = current->prev; list; list = list->prev)
2911 GtkTreeViewColumnCellInfo *inf = list->data;
2912 if (inf->pack == GTK_PACK_START)
2920 _gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column,
2927 count = _gtk_tree_view_column_count_special_cells (tree_column);
2929 /* if we are the current focus column and have multiple editable cells,
2930 * try to select the next one, else move the focus to the next column
2932 if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
2937 GList *list = tree_column->cell_list;
2938 GtkTreeViewColumnCellInfo *info = NULL;
2940 /* find current focussed cell */
2941 for ( ; list; list = list->next)
2944 if (info->has_focus)
2948 /* not a focussed cell in the focus column? */
2949 if (!list || !info || !info->has_focus)
2952 next = gtk_tree_view_column_cell_next (tree_column, list);
2953 prev = gtk_tree_view_column_cell_prev (tree_column, list);
2955 info->has_focus = FALSE;
2956 if (direction > 0 && next)
2959 info->has_focus = TRUE;
2962 else if (direction > 0 && !next && !right)
2964 /* keep focus on latest cell */
2965 info = gtk_tree_view_column_cell_last (tree_column)->data;
2966 info->has_focus = TRUE;
2969 else if (direction < 0 && prev)
2972 info->has_focus = TRUE;
2975 else if (direction < 0 && !prev && !left)
2977 /* keep focus on first cell */
2978 info = gtk_tree_view_column_cell_first (tree_column)->data;
2979 info->has_focus = TRUE;
2986 /* we get focus, if we have multiple editable cells, give the correct one
2991 GList *list = tree_column->cell_list;
2993 /* clear focus first */
2994 for ( ; list ; list = list->next)
2996 GtkTreeViewColumnCellInfo *info = list->data;
2997 if (info->has_focus)
2998 info->has_focus = FALSE;
3002 ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_first (tree_column)->data)->has_focus = TRUE;
3003 else if (direction < 0)
3004 ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_last (tree_column)->data)->has_focus = TRUE;
3010 _gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column,
3012 GdkRectangle *background_area,
3013 GdkRectangle *cell_area,
3014 GdkRectangle *expose_area,
3017 gint focus_line_width;
3018 GtkStateType cell_state;
3020 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3021 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3022 "focus-line-width", &focus_line_width, NULL);
3023 if (tree_column->editable_widget)
3025 /* This function is only called on the editable row when editing.
3028 gtk_paint_focus (tree_column->tree_view->style,
3030 GTK_WIDGET_STATE (tree_column->tree_view),
3032 tree_column->tree_view,
3034 cell_area->x - focus_line_width,
3035 cell_area->y - focus_line_width,
3036 cell_area->width + 2 * focus_line_width,
3037 cell_area->height + 2 * focus_line_width);
3042 GdkRectangle focus_rectangle;
3043 gtk_tree_view_column_cell_process_action (tree_column,
3053 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3054 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3055 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3056 gtk_paint_focus (tree_column->tree_view->style,
3060 tree_column->tree_view,
3064 focus_rectangle.width,
3065 focus_rectangle.height);
3070 * gtk_tree_view_column_cell_is_visible:
3071 * @tree_column: A #GtkTreeViewColumn
3073 * Returns #TRUE if any of the cells packed into the @tree_column are visible.
3074 * For this to be meaningful, you must first initialize the cells with
3075 * gtk_tree_view_column_cell_set_cell_data()
3077 * Return value: #TRUE, if any of the cells packed into the @tree_column are currently visible
3080 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
3084 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
3086 for (list = tree_column->cell_list; list; list = list->next)
3088 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3090 if (info->cell->visible)
3098 * gtk_tree_view_column_focus_cell:
3099 * @tree_view: A #GtkTreeView
3100 * @cell: A #GtkCellRenderer
3102 * Sets the current keyboard focus to be at @cell, if the column contains
3103 * 2 or more editable and activatable cells.
3106 gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
3107 GtkCellRenderer *cell)
3110 gboolean found_cell = FALSE;
3112 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3113 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3115 if (_gtk_tree_view_column_count_special_cells (tree_column) < 2)
3118 for (list = tree_column->cell_list; list; list = list->next)
3120 GtkTreeViewColumnCellInfo *info = list->data;
3122 if (info->cell == cell)
3124 info->has_focus = TRUE;
3132 for (list = tree_column->cell_list; list; list = list->next)
3134 GtkTreeViewColumnCellInfo *info = list->data;
3136 if (info->cell != cell)
3137 info->has_focus = FALSE;
3140 /* FIXME: redraw? */
3145 _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
3146 gboolean install_handler)
3150 for (list = tree_column->cell_list; list; list = list->next)
3152 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3154 info->requested_width = 0;
3156 tree_column->dirty = TRUE;
3157 tree_column->resized_width = MAX (tree_column->requested_width, tree_column->button_request);
3158 tree_column->requested_width = -1;
3159 tree_column->width = 0;
3161 if (tree_column->tree_view &&
3162 GTK_WIDGET_REALIZED (tree_column->tree_view))
3164 if (install_handler)
3165 _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
3167 GTK_TREE_VIEW (tree_column->tree_view)->priv->mark_rows_col_dirty = TRUE;
3168 gtk_widget_queue_resize (tree_column->tree_view);
3173 _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
3174 GtkCellEditable *cell_editable)
3176 g_return_if_fail (tree_column->editable_widget == NULL);
3178 tree_column->editable_widget = cell_editable;
3182 _gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column)
3186 g_return_if_fail (tree_column->editable_widget != NULL);
3188 tree_column->editable_widget = NULL;
3189 for (list = tree_column->cell_list; list; list = list->next)
3190 ((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3194 _gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column,
3195 GtkCellRenderer *cell,
3204 list = gtk_tree_view_column_cell_first (column);
3206 for (; list; list = gtk_tree_view_column_cell_next (column, list))
3208 GtkTreeViewColumnCellInfo *info =
3209 (GtkTreeViewColumnCellInfo *)list->data;
3211 if (info->cell == cell)
3214 *left += info->real_width;
3223 list = gtk_tree_view_column_cell_first (column);
3225 for (; list; list = gtk_tree_view_column_cell_next (column, list))
3227 GtkTreeViewColumnCellInfo *info =
3228 (GtkTreeViewColumnCellInfo *)list->data;
3230 if (info->cell == cell)
3235 next = gtk_tree_view_column_cell_next (column, list);
3239 for ( ; list; list = gtk_tree_view_column_cell_next (column, list))
3241 GtkTreeViewColumnCellInfo *info =
3242 (GtkTreeViewColumnCellInfo *)list->data;
3244 *right += info->real_width;