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,
126 static GtkObjectClass *parent_class = NULL;
127 static guint tree_column_signals[LAST_SIGNAL] = { 0 };
131 gtk_tree_view_column_get_type (void)
133 static GtkType tree_column_type = 0;
135 if (!tree_column_type)
137 static const GTypeInfo tree_column_info =
139 sizeof (GtkTreeViewColumnClass),
140 NULL, /* base_init */
141 NULL, /* base_finalize */
142 (GClassInitFunc) gtk_tree_view_column_class_init,
143 NULL, /* class_finalize */
144 NULL, /* class_data */
145 sizeof (GtkTreeViewColumn),
147 (GInstanceInitFunc) gtk_tree_view_column_init,
150 tree_column_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn", &tree_column_info, 0);
153 return tree_column_type;
157 gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
159 GObjectClass *object_class;
161 object_class = (GObjectClass*) class;
163 parent_class = g_type_class_peek_parent (class);
165 class->clicked = NULL;
167 object_class->finalize = gtk_tree_view_column_finalize;
168 object_class->set_property = gtk_tree_view_column_set_property;
169 object_class->get_property = gtk_tree_view_column_get_property;
171 tree_column_signals[CLICKED] =
172 g_signal_new ("clicked",
173 GTK_CLASS_TYPE (object_class),
175 G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
177 _gtk_marshal_VOID__VOID,
180 g_object_class_install_property (object_class,
182 g_param_spec_boolean ("visible",
184 _("Whether to display the column"),
186 G_PARAM_READABLE | G_PARAM_WRITABLE));
188 g_object_class_install_property (object_class,
190 g_param_spec_boolean ("resizable",
192 _("Column is user-resizable"),
194 G_PARAM_READABLE | G_PARAM_WRITABLE));
196 g_object_class_install_property (object_class,
198 g_param_spec_int ("width",
200 _("Current width of the column"),
205 g_object_class_install_property (object_class,
207 g_param_spec_enum ("sizing",
209 _("Resize mode of the column"),
210 GTK_TYPE_TREE_VIEW_COLUMN_SIZING,
211 GTK_TREE_VIEW_COLUMN_AUTOSIZE,
212 G_PARAM_READABLE | G_PARAM_WRITABLE));
214 g_object_class_install_property (object_class,
216 g_param_spec_int ("fixed_width",
218 _("Current fixed width of the column"),
222 G_PARAM_READABLE | G_PARAM_WRITABLE));
224 g_object_class_install_property (object_class,
226 g_param_spec_int ("min_width",
228 _("Minimum allowed width of the column"),
232 G_PARAM_READABLE | G_PARAM_WRITABLE));
234 g_object_class_install_property (object_class,
236 g_param_spec_int ("max_width",
238 _("Maximum allowed width of the column"),
242 G_PARAM_READABLE | G_PARAM_WRITABLE));
244 g_object_class_install_property (object_class,
246 g_param_spec_string ("title",
248 _("Title to appear in column header"),
250 G_PARAM_READABLE | G_PARAM_WRITABLE));
252 g_object_class_install_property (object_class,
254 g_param_spec_boolean ("clickable",
256 _("Whether the header can be clicked"),
258 G_PARAM_READABLE | G_PARAM_WRITABLE));
261 g_object_class_install_property (object_class,
263 g_param_spec_object ("widget",
265 _("Widget to put in column header button instead of column title"),
267 G_PARAM_READABLE | G_PARAM_WRITABLE));
269 g_object_class_install_property (object_class,
271 g_param_spec_float ("alignment",
273 _("X Alignment of the column header text or widget"),
277 G_PARAM_READABLE | G_PARAM_WRITABLE));
279 g_object_class_install_property (object_class,
281 g_param_spec_boolean ("reorderable",
283 _("Whether the column can be reordered around the headers"),
285 G_PARAM_READABLE | G_PARAM_WRITABLE));
287 g_object_class_install_property (object_class,
289 g_param_spec_boolean ("sort_indicator",
291 _("Whether to show a sort indicator"),
293 G_PARAM_READABLE | G_PARAM_WRITABLE));
295 g_object_class_install_property (object_class,
297 g_param_spec_enum ("sort_order",
299 _("Sort direction the sort indicator should indicate"),
302 G_PARAM_READABLE | G_PARAM_WRITABLE));
307 gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
309 tree_column->button = NULL;
310 tree_column->xalign = 0.0;
311 tree_column->width = 0;
312 tree_column->requested_width = -1;
313 tree_column->min_width = -1;
314 tree_column->max_width = -1;
315 tree_column->resized_width = 0;
316 tree_column->column_type = GTK_TREE_VIEW_COLUMN_GROW_ONLY;
317 tree_column->visible = TRUE;
318 tree_column->resizable = FALSE;
319 tree_column->clickable = FALSE;
320 tree_column->dirty = TRUE;
321 tree_column->sort_order = GTK_SORT_ASCENDING;
322 tree_column->show_sort_indicator = FALSE;
323 tree_column->property_changed_signal = 0;
324 tree_column->sort_clicked_signal = 0;
325 tree_column->sort_column_changed_signal = 0;
326 tree_column->sort_column_id = -1;
327 tree_column->reorderable = FALSE;
328 tree_column->maybe_reordered = FALSE;
329 tree_column->use_resized_width = FALSE;
333 gtk_tree_view_column_finalize (GObject *object)
335 GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
338 for (list = tree_column->cell_list; list; list = list->next)
340 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
344 GtkDestroyNotify d = info->destroy;
346 info->destroy = NULL;
349 gtk_tree_view_column_clear_attributes (tree_column, info->cell);
350 g_object_unref (G_OBJECT (info->cell));
354 g_free (tree_column->title);
356 G_OBJECT_CLASS (parent_class)->finalize (object);
360 gtk_tree_view_column_set_property (GObject *object,
365 GtkTreeViewColumn *tree_column;
367 tree_column = GTK_TREE_VIEW_COLUMN (object);
372 gtk_tree_view_column_set_visible (tree_column,
373 g_value_get_boolean (value));
377 gtk_tree_view_column_set_resizable (tree_column,
378 g_value_get_boolean (value));
382 gtk_tree_view_column_set_sizing (tree_column,
383 g_value_get_enum (value));
386 case PROP_FIXED_WIDTH:
387 gtk_tree_view_column_set_fixed_width (tree_column,
388 g_value_get_int (value));
392 gtk_tree_view_column_set_min_width (tree_column,
393 g_value_get_int (value));
397 gtk_tree_view_column_set_max_width (tree_column,
398 g_value_get_int (value));
402 gtk_tree_view_column_set_title (tree_column,
403 g_value_get_string (value));
407 gtk_tree_view_column_set_clickable (tree_column,
408 g_value_get_boolean (value));
412 gtk_tree_view_column_set_widget (tree_column,
413 (GtkWidget*) g_value_get_object (value));
417 gtk_tree_view_column_set_alignment (tree_column,
418 g_value_get_float (value));
421 case PROP_REORDERABLE:
422 gtk_tree_view_column_set_reorderable (tree_column,
423 g_value_get_boolean (value));
426 case PROP_SORT_INDICATOR:
427 gtk_tree_view_column_set_sort_indicator (tree_column,
428 g_value_get_boolean (value));
431 case PROP_SORT_ORDER:
432 gtk_tree_view_column_set_sort_order (tree_column,
433 g_value_get_enum (value));
437 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
443 gtk_tree_view_column_get_property (GObject *object,
448 GtkTreeViewColumn *tree_column;
450 tree_column = GTK_TREE_VIEW_COLUMN (object);
455 g_value_set_boolean (value,
456 gtk_tree_view_column_get_visible (tree_column));
460 g_value_set_boolean (value,
461 gtk_tree_view_column_get_resizable (tree_column));
465 g_value_set_int (value,
466 gtk_tree_view_column_get_width (tree_column));
470 g_value_set_enum (value,
471 gtk_tree_view_column_get_sizing (tree_column));
474 case PROP_FIXED_WIDTH:
475 g_value_set_int (value,
476 gtk_tree_view_column_get_fixed_width (tree_column));
480 g_value_set_int (value,
481 gtk_tree_view_column_get_min_width (tree_column));
485 g_value_set_int (value,
486 gtk_tree_view_column_get_max_width (tree_column));
490 g_value_set_string (value,
491 gtk_tree_view_column_get_title (tree_column));
495 g_value_set_boolean (value,
496 gtk_tree_view_column_get_clickable (tree_column));
500 g_value_set_object (value,
501 (GObject*) gtk_tree_view_column_get_widget (tree_column));
505 g_value_set_float (value,
506 gtk_tree_view_column_get_alignment (tree_column));
509 case PROP_REORDERABLE:
510 g_value_set_boolean (value,
511 gtk_tree_view_column_get_reorderable (tree_column));
514 case PROP_SORT_INDICATOR:
515 g_value_set_boolean (value,
516 gtk_tree_view_column_get_sort_indicator (tree_column));
519 case PROP_SORT_ORDER:
520 g_value_set_enum (value,
521 gtk_tree_view_column_get_sort_order (tree_column));
525 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
533 /* Button handling code
536 gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
538 GtkTreeView *tree_view;
542 tree_view = (GtkTreeView *) tree_column->tree_view;
544 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
545 g_return_if_fail (tree_column->button == NULL);
547 gtk_widget_push_composite_child ();
548 tree_column->button = gtk_button_new ();
549 gtk_widget_add_events (tree_column->button, GDK_POINTER_MOTION_MASK);
550 gtk_widget_pop_composite_child ();
552 /* make sure we own a reference to it as well. */
553 if (tree_view->priv->header_window)
554 gtk_widget_set_parent_window (tree_column->button, tree_view->priv->header_window);
555 gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
557 g_signal_connect (G_OBJECT (tree_column->button), "event",
558 G_CALLBACK (gtk_tree_view_column_button_event),
559 (gpointer) tree_column);
560 g_signal_connect (G_OBJECT (tree_column->button), "clicked",
561 (GtkSignalFunc) gtk_tree_view_column_button_clicked,
562 (gpointer) tree_column);
564 tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
566 hbox = gtk_hbox_new (FALSE, 2);
567 tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
569 if (tree_column->child)
570 child = tree_column->child;
573 child = gtk_label_new (tree_column->title);
574 gtk_widget_show (child);
577 g_signal_connect (G_OBJECT (child), "mnemonic_activate",
578 G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
579 (gpointer) tree_column);
581 if (tree_column->xalign <= 0.5)
582 gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
584 gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
586 gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
588 gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
589 gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
591 gtk_widget_show (hbox);
592 gtk_widget_show (tree_column->alignment);
593 gtk_tree_view_column_update_button (tree_column);
597 gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
600 GtkWidget *alignment;
602 GtkWidget *current_child;
604 /* Create a button if necessary */
605 if (tree_column->visible &&
606 tree_column->button == NULL &&
607 tree_column->tree_view &&
608 GTK_WIDGET_REALIZED (tree_column->tree_view))
609 gtk_tree_view_column_create_button (tree_column);
611 if (! tree_column->button)
614 hbox = GTK_BIN (tree_column->button)->child;
615 alignment = tree_column->alignment;
616 arrow = tree_column->arrow;
617 current_child = GTK_BIN (alignment)->child;
619 /* Set up the actual button */
620 gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
623 if (tree_column->child)
625 if (current_child != tree_column->child)
627 gtk_container_remove (GTK_CONTAINER (alignment),
629 gtk_container_add (GTK_CONTAINER (alignment),
635 if (current_child == NULL)
637 current_child = gtk_label_new (NULL);
638 gtk_widget_show (current_child);
639 gtk_container_add (GTK_CONTAINER (alignment),
643 g_return_if_fail (GTK_IS_LABEL (current_child));
645 if (tree_column->title)
646 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
649 gtk_label_set_text_with_mnemonic (GTK_LABEL (current_child),
653 switch (tree_column->sort_order)
655 case GTK_SORT_ASCENDING:
656 gtk_arrow_set (GTK_ARROW (arrow),
661 case GTK_SORT_DESCENDING:
662 gtk_arrow_set (GTK_ARROW (arrow),
668 g_warning (G_STRLOC": bad sort order");
672 /* Put arrow on the right if the text is left-or-center justified, and on the
673 * left otherwise; do this by packing boxes, so flipping text direction will
676 gtk_widget_ref (arrow);
677 gtk_container_remove (GTK_CONTAINER (hbox), arrow);
679 if (tree_column->xalign <= 0.5)
681 gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
686 /* move it to the front */
687 gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
689 gtk_widget_unref (arrow);
691 if (tree_column->show_sort_indicator)
692 gtk_widget_show (arrow);
694 gtk_widget_hide (arrow);
696 /* It's always safe to hide the button. It isn't always safe to show it, as
697 * if you show it before it's realized, it'll get the wrong window. */
698 if (tree_column->button &&
699 tree_column->tree_view != NULL &&
700 GTK_WIDGET_REALIZED (tree_column->tree_view))
702 if (tree_column->visible)
704 gtk_widget_show_now (tree_column->button);
705 if (tree_column->window)
707 if (tree_column->resizable)
709 gdk_window_show (tree_column->window);
710 gdk_window_raise (tree_column->window);
714 gdk_window_hide (tree_column->window);
720 gtk_widget_hide (tree_column->button);
721 if (tree_column->window)
722 gdk_window_hide (tree_column->window);
726 if (tree_column->reorderable || tree_column->clickable)
728 GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
732 GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
733 if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
735 GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
736 if (GTK_WIDGET_TOPLEVEL (toplevel))
738 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
742 /* Queue a resize on the assumption that we always want to catch all changes
743 * and columns don't change all that often.
745 if (GTK_WIDGET_REALIZED (tree_column->tree_view))
746 gtk_widget_queue_resize (tree_column->tree_view);
750 /* Button signal handlers
754 gtk_tree_view_column_button_event (GtkWidget *widget,
758 GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
760 g_return_val_if_fail (event != NULL, FALSE);
762 if (event->type == GDK_BUTTON_PRESS &&
765 column->maybe_reordered = TRUE;
766 gdk_window_get_pointer (widget->window,
770 gtk_widget_grab_focus (widget);
773 if (event->type == GDK_BUTTON_RELEASE &&
774 column->maybe_reordered)
775 column->maybe_reordered = FALSE;
777 if (event->type == GDK_MOTION_NOTIFY &&
778 (column->maybe_reordered) &&
779 (gtk_drag_check_threshold (widget,
782 (gint) ((GdkEventMotion *)event)->x,
783 (gint) ((GdkEventMotion *)event)->y)))
785 column->maybe_reordered = FALSE;
786 /* this is to change our drag_x to be relative to
787 * tree_view->priv->bin_window, instead of our window.
789 column->drag_x -= column->button->allocation.x;
790 _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
793 if (column->clickable == FALSE)
797 case GDK_BUTTON_PRESS:
798 case GDK_2BUTTON_PRESS:
799 case GDK_3BUTTON_PRESS:
800 case GDK_MOTION_NOTIFY:
801 case GDK_BUTTON_RELEASE:
802 case GDK_ENTER_NOTIFY:
803 case GDK_LEAVE_NOTIFY:
814 gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
816 g_signal_emit_by_name (G_OBJECT (data), "clicked");
820 gtk_tree_view_column_mnemonic_activate (GtkWidget *widget,
821 gboolean group_cycling,
824 GtkTreeViewColumn *column = (GtkTreeViewColumn *)data;
826 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), FALSE);
828 GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column;
829 if (column->clickable)
830 gtk_button_clicked (GTK_BUTTON (column->button));
831 else if (GTK_WIDGET_CAN_FOCUS (column->button))
832 gtk_widget_grab_focus (column->button);
834 gtk_widget_grab_focus (column->tree_view);
840 gtk_tree_view_model_sort_column_changed (GtkTreeSortable *sortable,
841 GtkTreeViewColumn *column)
846 if (gtk_tree_sortable_get_sort_column_id (sortable,
850 if (sort_column_id == column->sort_column_id)
852 gtk_tree_view_column_set_sort_indicator (column, TRUE);
853 gtk_tree_view_column_set_sort_order (column, order);
857 gtk_tree_view_column_set_sort_indicator (column, FALSE);
862 gtk_tree_view_column_set_sort_indicator (column, FALSE);
867 gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
872 gboolean has_sort_column;
873 gboolean has_default_sort_func;
875 g_return_if_fail (tree_column->tree_view != NULL);
878 gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
881 has_default_sort_func =
882 gtk_tree_sortable_has_default_sort_func (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model));
884 if (has_sort_column &&
885 sort_column_id == tree_column->sort_column_id)
887 if (order == GTK_SORT_ASCENDING)
888 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
889 tree_column->sort_column_id,
890 GTK_SORT_DESCENDING);
891 else if (order == GTK_SORT_DESCENDING && has_default_sort_func)
892 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
893 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
896 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
897 tree_column->sort_column_id,
902 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
903 tree_column->sort_column_id,
910 gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
914 if (tree_column->tree_view == NULL)
917 model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
922 if (GTK_IS_TREE_SORTABLE (model) &&
923 tree_column->sort_column_id != -1)
925 gint real_sort_column_id;
926 GtkSortType real_order;
928 if (tree_column->sort_column_changed_signal == 0)
929 tree_column->sort_column_changed_signal =
930 g_signal_connect (G_OBJECT (model), "sort_column_changed",
931 GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
934 if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
935 &real_sort_column_id,
937 (real_sort_column_id == tree_column->sort_column_id))
939 gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
940 gtk_tree_view_column_set_sort_order (tree_column, real_order);
948 /* Exported Private Functions.
949 * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
953 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
955 GtkTreeView *tree_view;
957 guint attributes_mask;
959 tree_view = (GtkTreeView *)column->tree_view;
961 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
962 g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
963 g_return_if_fail (tree_view->priv->header_window != NULL);
964 g_return_if_fail (column->button != NULL);
966 gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
969 gtk_widget_show (column->button);
971 attr.window_type = GDK_WINDOW_CHILD;
972 attr.wclass = GDK_INPUT_ONLY;
973 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
974 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
975 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
976 attr.event_mask = (GDK_BUTTON_PRESS_MASK |
977 GDK_BUTTON_RELEASE_MASK |
978 GDK_POINTER_MOTION_MASK |
979 GDK_POINTER_MOTION_HINT_MASK |
981 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
982 attr.cursor = gdk_cursor_new_for_screen (gdk_drawable_get_screen (tree_view->priv->header_window),
983 GDK_SB_H_DOUBLE_ARROW);
985 attr.width = TREE_VIEW_DRAG_WIDTH;
986 attr.height = tree_view->priv->header_height;
988 attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
990 column->window = gdk_window_new (tree_view->priv->header_window,
991 &attr, attributes_mask);
992 gdk_window_set_user_data (column->window, tree_view);
994 gtk_tree_view_column_update_button (column);
996 gdk_cursor_unref (attr.cursor);
1000 _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
1002 g_return_if_fail (column != NULL);
1003 g_return_if_fail (column->window != NULL);
1005 gdk_window_set_user_data (column->window, NULL);
1006 gdk_window_destroy (column->window);
1007 column->window = NULL;
1011 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
1012 GtkTreeView *tree_view)
1014 g_assert (column->tree_view == NULL);
1016 column->tree_view = GTK_WIDGET (tree_view);
1017 gtk_tree_view_column_create_button (column);
1019 column->property_changed_signal =
1020 g_signal_connect_swapped (GTK_OBJECT (tree_view),
1022 GTK_SIGNAL_FUNC (gtk_tree_view_column_setup_sort_column_id_callback),
1025 gtk_tree_view_column_setup_sort_column_id_callback (column);
1029 _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
1031 if (column->tree_view && column->button)
1033 gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
1035 if (column->property_changed_signal)
1037 g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
1038 column->property_changed_signal = 0;
1041 if (column->sort_column_changed_signal)
1043 g_signal_handler_disconnect (G_OBJECT (gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view))),
1044 column->sort_column_changed_signal);
1045 column->sort_column_changed_signal = 0;
1048 column->tree_view = NULL;
1049 column->button = NULL;
1053 _gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
1057 for (list = column->cell_list; list; list = list->next)
1058 if (((GtkTreeViewColumnCellInfo *)list->data)->cell->mode ==
1059 GTK_CELL_RENDERER_MODE_EDITABLE)
1065 /* gets cell being edited */
1067 _gtk_tree_view_column_get_edited_cell (GtkTreeViewColumn *column)
1071 for (list = column->cell_list; list; list = list->next)
1072 if (((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode)
1073 return ((GtkTreeViewColumnCellInfo *)list->data)->cell;
1079 _gtk_tree_view_column_count_special_cells (GtkTreeViewColumn *column)
1084 for (list = column->cell_list; list; list = list->next)
1086 GtkTreeViewColumnCellInfo *cellinfo = list->data;
1088 if (cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
1089 cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
1097 _gtk_tree_view_column_get_cell_at_pos (GtkTreeViewColumn *column,
1103 list = gtk_tree_view_column_cell_first (column);
1104 for (; list; list = gtk_tree_view_column_cell_next (column, list))
1106 GtkTreeViewColumnCellInfo *cellinfo = list->data;
1107 if (current_x <= x && x <= current_x + cellinfo->real_width)
1108 return cellinfo->cell;
1109 current_x += cellinfo->real_width;
1115 /* Public Functions */
1119 * gtk_tree_view_column_new:
1121 * Creates a new #GtkTreeViewColumn.
1123 * Return value: A newly created #GtkTreeViewColumn.
1126 gtk_tree_view_column_new (void)
1128 GtkTreeViewColumn *tree_column;
1130 tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
1136 * gtk_tree_view_column_new_with_attributes:
1137 * @title: The title to set the header to.
1138 * @cell: The #GtkCellRenderer.
1139 * @Varargs: A %NULL-terminated list of attributes.
1141 * Creates a new #GtkTreeViewColumn with a number of default values. This is
1142 * equivalent to calling gtk_tree_view_column_set_title(),
1143 * gtk_tree_view_column_pack_start(), and
1144 * gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
1146 * Here's a simple example:
1147 * <informalexample><programlisting>
1148 * enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
1151 * GtkTreeViewColumn *column;
1152 * GtkCellRenderer *renderer = gtk_cell_renderer_text_new (<!-- -->);
1154 * column = gtk_tree_view_column_new_with_attributes ("Title",
1156 * "text", TEXT_COLUMN,
1157 * "foreground", COLOR_COLUMN,
1160 * </programlisting></informalexample>
1162 * Return value: A newly created #GtkTreeViewColumn.
1165 gtk_tree_view_column_new_with_attributes (const gchar *title,
1166 GtkCellRenderer *cell,
1169 GtkTreeViewColumn *retval;
1172 retval = gtk_tree_view_column_new ();
1174 gtk_tree_view_column_set_title (retval, title);
1175 gtk_tree_view_column_pack_start (retval, cell, TRUE);
1177 va_start (args, cell);
1178 gtk_tree_view_column_set_attributesv (retval, cell, args);
1184 static GtkTreeViewColumnCellInfo *
1185 gtk_tree_view_column_get_cell_info (GtkTreeViewColumn *tree_column,
1186 GtkCellRenderer *cell_renderer)
1189 for (list = tree_column->cell_list; list; list = list->next)
1190 if (((GtkTreeViewColumnCellInfo *)list->data)->cell == cell_renderer)
1191 return (GtkTreeViewColumnCellInfo *) list->data;
1197 * gtk_tree_view_column_pack_start:
1198 * @tree_column: A #GtkTreeViewColumn.
1199 * @cell: The #GtkCellRenderer.
1200 * @expand: %TRUE if @cell is to be given extra space allocated to box.
1202 * Packs the @cell into the beginning column. If @expand is %TRUE, then the
1203 * @cell is allocated a share of all available space that the @tree_column has.
1206 gtk_tree_view_column_pack_start (GtkTreeViewColumn *tree_column,
1207 GtkCellRenderer *cell,
1210 GtkTreeViewColumnCellInfo *cell_info;
1212 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1213 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1214 g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1216 g_object_ref (G_OBJECT (cell));
1217 gtk_object_sink (GTK_OBJECT (cell));
1219 cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1220 cell_info->cell = cell;
1221 cell_info->expand = expand ? TRUE : FALSE;
1222 cell_info->pack = GTK_PACK_START;
1223 cell_info->has_focus = 0;
1224 cell_info->attributes = NULL;
1226 tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1230 * gtk_tree_view_column_pack_end:
1231 * @tree_column: A #GtkTreeViewColumn.
1232 * @cell: The #GtkCellRenderer.
1233 * @expand: %TRUE if @cell is to be given extra space allocated to box.
1235 * Packs the @cell into the column. If @expand is %TRUE, then the @cell is
1236 * allocated a share of all available space that the @tree_column has.
1239 gtk_tree_view_column_pack_end (GtkTreeViewColumn *tree_column,
1240 GtkCellRenderer *cell,
1243 GtkTreeViewColumnCellInfo *cell_info;
1245 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1246 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
1247 g_return_if_fail (! gtk_tree_view_column_get_cell_info (tree_column, cell));
1249 g_object_ref (G_OBJECT (cell));
1250 gtk_object_sink (GTK_OBJECT (cell));
1252 cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
1253 cell_info->cell = cell;
1254 cell_info->expand = expand ? TRUE : FALSE;
1255 cell_info->pack = GTK_PACK_END;
1256 cell_info->has_focus = 0;
1257 cell_info->attributes = NULL;
1259 tree_column->cell_list = g_list_append (tree_column->cell_list, cell_info);
1264 * gtk_tree_view_column_clear:
1265 * @tree_column: A #GtkTreeViewColumn
1267 * Unsets all the mappings on all renderers on the @tree_column.
1270 gtk_tree_view_column_clear (GtkTreeViewColumn *tree_column)
1273 g_return_if_fail (tree_column != NULL);
1275 for (list = tree_column->cell_list; list; list = list->next)
1277 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1279 gtk_tree_view_column_clear_attributes (tree_column, info->cell);
1280 g_object_unref (G_OBJECT (info->cell));
1284 g_list_free (tree_column->cell_list);
1285 tree_column->cell_list = NULL;
1289 * gtk_tree_view_column_get_cell_renderers:
1290 * @tree_column: A #GtkTreeViewColumn
1292 * Returns a newly-allocated #GList of all the cell renderers in the column,
1293 * in no particular order. The list must be freed with g_list_free().
1295 * Return value: A list of #GtkCellRenderers
1298 gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
1300 GList *retval = NULL, *list;
1302 g_return_val_if_fail (tree_column != NULL, NULL);
1304 for (list = tree_column->cell_list; list; list = list->next)
1306 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
1308 retval = g_list_append (retval, info->cell);
1315 * gtk_tree_view_column_add_attribute:
1316 * @tree_column: A #GtkTreeViewColumn.
1317 * @cell_renderer: the #GtkCellRenderer to set attributes on
1318 * @attribute: An attribute on the renderer
1319 * @column: The column position on the model to get the attribute from.
1321 * Adds an attribute mapping to the list in @tree_column. The @column is the
1322 * column of the model to get a value from, and the @attribute is the
1323 * parameter on @cell_renderer to be set from the value. So for example
1324 * if column 2 of the model contains strings, you could have the
1325 * "text" attribute of a #GtkCellRendererText get its values from
1329 gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
1330 GtkCellRenderer *cell_renderer,
1331 const gchar *attribute,
1334 GtkTreeViewColumnCellInfo *info;
1336 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1337 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1338 g_return_if_fail (info != NULL);
1340 info->attributes = g_slist_prepend (info->attributes, GINT_TO_POINTER (column));
1341 info->attributes = g_slist_prepend (info->attributes, g_strdup (attribute));
1343 if (tree_column->tree_view)
1344 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1349 gtk_tree_view_column_set_attributesv (GtkTreeViewColumn *tree_column,
1350 GtkCellRenderer *cell_renderer,
1356 attribute = va_arg (args, gchar *);
1358 gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1360 while (attribute != NULL)
1362 column = va_arg (args, gint);
1363 gtk_tree_view_column_add_attribute (tree_column, cell_renderer, attribute, column);
1364 attribute = va_arg (args, gchar *);
1369 * gtk_tree_view_column_set_attributes:
1370 * @tree_column: A #GtkTreeViewColumn.
1371 * @cell_renderer: the #GtkCellRenderer we're setting the attributes of
1372 * @Varargs: A %NULL-terminated list of attributes.
1374 * Sets the attributes in the list as the attributes of @tree_column.
1375 * The attributes should be in attribute/column order, as in
1376 * gtk_tree_view_column_add_attribute(). All existing attributes
1377 * are removed, and replaced with the new attributes.
1380 gtk_tree_view_column_set_attributes (GtkTreeViewColumn *tree_column,
1381 GtkCellRenderer *cell_renderer,
1386 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1387 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1388 g_return_if_fail (gtk_tree_view_column_get_cell_info (tree_column, cell_renderer));
1390 va_start (args, cell_renderer);
1391 gtk_tree_view_column_set_attributesv (tree_column, cell_renderer, args);
1397 * gtk_tree_view_column_set_cell_data_func:
1398 * @tree_column: A #GtkTreeViewColumn
1399 * @cell_renderer: A #GtkCellRenderer
1400 * @func: The #GtkTreeViewColumnFunc to use.
1401 * @func_data: The user data for @func.
1402 * @destroy: The destroy notification for @func_data
1404 * Sets the #GtkTreeViewColumnFunc to use for the column. This
1405 * function is used instead of the standard attributes mapping for
1406 * setting the column value, and should set the value of @tree_column's
1407 * cell renderer as appropriate. @func may be %NULL to remove an
1411 gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn *tree_column,
1412 GtkCellRenderer *cell_renderer,
1413 GtkTreeCellDataFunc func,
1415 GtkDestroyNotify destroy)
1417 GtkTreeViewColumnCellInfo *info;
1419 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1420 g_return_if_fail (GTK_IS_CELL_RENDERER (cell_renderer));
1421 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1423 g_return_if_fail (info != NULL);
1427 GtkDestroyNotify d = info->destroy;
1429 info->destroy = NULL;
1430 d (info->func_data);
1434 info->func_data = func_data;
1435 info->destroy = destroy;
1437 if (tree_column->tree_view)
1438 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1443 * gtk_tree_view_column_clear_attributes:
1444 * @tree_column: a #GtkTreeViewColumn
1445 * @cell_renderer: a #GtkCellRenderer to clear the attribute mapping on.
1447 * Clears all existing attributes previously set with
1448 * gtk_tree_view_column_set_attributes().
1451 gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column,
1452 GtkCellRenderer *cell_renderer)
1454 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));
1459 info = gtk_tree_view_column_get_cell_info (tree_column, cell_renderer);
1461 list = info->attributes;
1463 while (list && list->next)
1465 g_free (list->data);
1466 list = list->next->next;
1468 g_slist_free (info->attributes);
1469 info->attributes = NULL;
1471 if (tree_column->tree_view)
1472 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1477 * gtk_tree_view_column_set_spacing:
1478 * @tree_column: A #GtkTreeViewColumn.
1479 * @spacing: distance between cell renderers in pixels.
1481 * Sets the spacing field of @tree_column, which is the number of pixels to
1482 * place between cell renderers packed into it.
1485 gtk_tree_view_column_set_spacing (GtkTreeViewColumn *tree_column,
1488 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1489 g_return_if_fail (spacing >= 0);
1491 if (tree_column->spacing == spacing)
1494 tree_column->spacing = spacing;
1495 if (tree_column->tree_view)
1496 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1500 * gtk_tree_view_column_get_spacing:
1501 * @tree_column: A #GtkTreeViewColumn.
1503 * Returns the spacing of @tree_column.
1505 * Return value: the spacing of @tree_column.
1508 gtk_tree_view_column_get_spacing (GtkTreeViewColumn *tree_column)
1510 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1512 return tree_column->spacing;
1515 /* Options for manipulating the columns */
1518 * gtk_tree_view_column_set_visible:
1519 * @tree_column: A #GtkTreeViewColumn.
1520 * @visible: %TRUE if the @tree_column is visible.
1522 * Sets the visibility of @tree_column.
1525 gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
1528 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1530 visible = !! visible;
1532 if (tree_column->visible == visible)
1535 tree_column->visible = visible;
1537 if (tree_column->visible)
1538 _gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
1540 gtk_tree_view_column_update_button (tree_column);
1541 g_object_notify (G_OBJECT (tree_column), "visible");
1545 * gtk_tree_view_column_get_visible:
1546 * @tree_column: A #GtkTreeViewColumn.
1548 * Returns %TRUE if @tree_column is visible.
1550 * Return value: whether the column is visible or not. If it is visible, then
1551 * the tree will show the column.
1554 gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
1556 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1558 return tree_column->visible;
1562 * gtk_tree_view_column_set_resizable:
1563 * @tree_column: A #GtkTreeViewColumn
1564 * @resizable: %TRUE, if the column can be resized
1566 * If @resizable is %TRUE, then the user can explicitly resize the column by
1567 * grabbing the outer edge of the column button. If resizable is TRUE and
1568 * sizing mode of the column is #GTK_TREE_VIEW_COLUMN_AUTOSIZE, then the sizing
1569 * mode is changed to #GTK_TREE_VIEW_COLUMN_GROW_ONLY.
1572 gtk_tree_view_column_set_resizable (GtkTreeViewColumn *tree_column,
1575 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1577 resizable = !! resizable;
1579 if (tree_column->resizable == resizable)
1582 tree_column->resizable = resizable;
1584 if (resizable && tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1585 gtk_tree_view_column_set_sizing (tree_column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1587 gtk_tree_view_column_update_button (tree_column);
1589 g_object_notify (G_OBJECT (tree_column), "resizable");
1593 * gtk_tree_view_column_get_resizable:
1594 * @tree_column: A #GtkTreeViewColumn
1596 * Returns #TRUE if the @tree_column can be resized by the end user.
1598 * Return value: #TRUE, if the @tree_column can be resized.
1601 gtk_tree_view_column_get_resizable (GtkTreeViewColumn *tree_column)
1603 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1605 return tree_column->resizable;
1610 * gtk_tree_view_column_set_sizing:
1611 * @tree_column: A #GtkTreeViewColumn.
1612 * @type: The #GtkTreeViewColumnSizing.
1614 * Sets the growth behavior of @tree_column to @type.
1617 gtk_tree_view_column_set_sizing (GtkTreeViewColumn *tree_column,
1618 GtkTreeViewColumnSizing type)
1620 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1622 if (type == tree_column->column_type)
1625 if (type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1626 gtk_tree_view_column_set_resizable (tree_column, FALSE);
1629 /* I was clearly on crack when I wrote this. I'm not sure what's supposed to
1630 * be below so I'll leave it until I figure it out.
1632 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
1633 tree_column->requested_width != -1)
1635 gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
1638 tree_column->column_type = type;
1640 gtk_tree_view_column_update_button (tree_column);
1642 g_object_notify (G_OBJECT (tree_column), "sizing");
1646 * gtk_tree_view_column_get_sizing:
1647 * @tree_column: A #GtkTreeViewColumn.
1649 * Returns the current type of @tree_column.
1651 * Return value: The type of @tree_column.
1653 GtkTreeViewColumnSizing
1654 gtk_tree_view_column_get_sizing (GtkTreeViewColumn *tree_column)
1656 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1658 return tree_column->column_type;
1662 * gtk_tree_view_column_get_width:
1663 * @tree_column: A #GtkTreeViewColumn.
1665 * Returns the current size of @tree_column in pixels.
1667 * Return value: The current width of @tree_column.
1670 gtk_tree_view_column_get_width (GtkTreeViewColumn *tree_column)
1672 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1674 return tree_column->width;
1678 * gtk_tree_view_column_set_fixed_width:
1679 * @tree_column: A #GtkTreeViewColumn.
1680 * @fixed_width: The size to set @tree_column to. Must be greater than 0.
1682 * Sets the size of the column in pixels. This is meaningful only if the sizing
1683 * type is #GTK_TREE_VIEW_COLUMN_FIXED. The size of the column is clamped to
1684 * the min/max width for the column. Please note that the min/max width of the
1685 * column doesn't actually affect the "fixed_width" property of the widget, just
1686 * the actual size when displayed.
1689 gtk_tree_view_column_set_fixed_width (GtkTreeViewColumn *tree_column,
1692 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1693 g_return_if_fail (fixed_width > 0);
1695 tree_column->fixed_width = fixed_width;
1697 if (tree_column->tree_view &&
1698 GTK_WIDGET_REALIZED (tree_column->tree_view) &&
1699 tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
1701 gtk_widget_queue_resize (tree_column->tree_view);
1704 g_object_notify (G_OBJECT (tree_column), "fixed_width");
1708 * gtk_tree_view_column_get_fixed_width:
1709 * @tree_column: a #GtkTreeViewColumn
1711 * Gets the fixed width of the column. This value is only meaning may not be
1712 * the actual width of the column on the screen, just what is requested.
1714 * Return value: the fixed width of the column
1717 gtk_tree_view_column_get_fixed_width (GtkTreeViewColumn *tree_column)
1719 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
1721 return tree_column->fixed_width;
1725 * gtk_tree_view_column_set_min_width:
1726 * @tree_column: A #GtkTreeViewColumn.
1727 * @min_width: The minimum width of the column in pixels, or -1.
1729 * Sets the minimum width of the @tree_column. If @min_width is -1, then the
1730 * minimum width is unset.
1733 gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
1736 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1737 g_return_if_fail (min_width >= -1);
1739 if (min_width == tree_column->min_width)
1742 if (tree_column->visible &&
1743 tree_column->tree_view != NULL &&
1744 GTK_WIDGET_REALIZED (tree_column->tree_view))
1746 if (min_width > tree_column->width)
1747 gtk_widget_queue_resize (tree_column->tree_view);
1750 tree_column->min_width = min_width;
1751 g_object_freeze_notify (G_OBJECT (tree_column));
1752 if (tree_column->max_width != -1 && tree_column->max_width < min_width)
1754 tree_column->max_width = min_width;
1755 g_object_notify (G_OBJECT (tree_column), "max_width");
1757 g_object_notify (G_OBJECT (tree_column), "min_width");
1758 g_object_thaw_notify (G_OBJECT (tree_column));
1760 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1761 _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1766 * gtk_tree_view_column_get_min_width:
1767 * @tree_column: A #GtkTreeViewColumn.
1769 * Returns the minimum width in pixels of the @tree_column, or -1 if no minimum
1772 * Return value: The minimum width of the @tree_column.
1775 gtk_tree_view_column_get_min_width (GtkTreeViewColumn *tree_column)
1777 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1779 return tree_column->min_width;
1783 * gtk_tree_view_column_set_max_width:
1784 * @tree_column: A #GtkTreeViewColumn.
1785 * @max_width: The maximum width of the column in pixels, or -1.
1787 * Sets the maximum width of the @tree_column. If @max_width is -1, then the
1788 * maximum width is unset. Note, the column can actually be wider than max
1789 * width if it's the last column in a view. In this case, the column expands to
1790 * fill any extra space.
1793 gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
1796 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1797 g_return_if_fail (max_width >= -1);
1799 if (max_width == tree_column->max_width)
1802 if (tree_column->visible &&
1803 tree_column->tree_view != NULL &&
1804 GTK_WIDGET_REALIZED (tree_column->tree_view))
1806 if (max_width != -1 && max_width < tree_column->width)
1807 gtk_widget_queue_resize (tree_column->tree_view);
1810 tree_column->max_width = max_width;
1811 g_object_freeze_notify (G_OBJECT (tree_column));
1812 if (max_width != -1 && max_width < tree_column->min_width)
1814 tree_column->min_width = max_width;
1815 g_object_notify (G_OBJECT (tree_column), "min_width");
1817 g_object_notify (G_OBJECT (tree_column), "max_width");
1818 g_object_thaw_notify (G_OBJECT (tree_column));
1820 if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
1821 _gtk_tree_view_column_autosize (GTK_TREE_VIEW (tree_column->tree_view),
1826 * gtk_tree_view_column_get_max_width:
1827 * @tree_column: A #GtkTreeViewColumn.
1829 * Returns the maximum width in pixels of the @tree_column, or -1 if no maximum
1832 * Return value: The maximum width of the @tree_column.
1835 gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
1837 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), -1);
1839 return tree_column->max_width;
1843 * gtk_tree_view_column_clicked:
1844 * @tree_column: a #GtkTreeViewColumn
1846 * Emits the "clicked" signal on the column. This function will only work if
1847 * @tree_column is clickable.
1850 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
1852 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1854 if (tree_column->visible &&
1855 tree_column->button &&
1856 tree_column->clickable)
1857 gtk_button_clicked (GTK_BUTTON (tree_column->button));
1861 * gtk_tree_view_column_set_title:
1862 * @tree_column: A #GtkTreeViewColumn.
1863 * @title: The title of the @tree_column.
1865 * Sets the title of the @tree_column. If a custom widget has been set, then
1866 * this value is ignored.
1869 gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
1872 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1874 g_free (tree_column->title);
1876 tree_column->title = g_strdup (title);
1878 tree_column->title = NULL;
1880 gtk_tree_view_column_update_button (tree_column);
1881 g_object_notify (G_OBJECT (tree_column), "title");
1885 * gtk_tree_view_column_get_title:
1886 * @tree_column: A #GtkTreeViewColumn.
1888 * Returns the title of the widget. This value should not be modified.
1890 * Return value: the title of the column.
1892 G_CONST_RETURN gchar *
1893 gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
1895 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1897 return tree_column->title;
1901 * gtk_tree_view_column_set_clickable:
1902 * @tree_column: A #GtkTreeViewColumn.
1903 * @clickable: %TRUE if the header is active.
1905 * Sets the header to be active if @active is %TRUE. When the header is active,
1906 * then it can take keyboard focus, and can be clicked.
1909 gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
1912 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1914 clickable = !! clickable;
1915 if (tree_column->clickable == clickable)
1918 tree_column->clickable = clickable;
1919 gtk_tree_view_column_update_button (tree_column);
1920 g_object_notify (G_OBJECT (tree_column), "clickable");
1924 * gtk_tree_view_column_get_clickable:
1925 * @tree_column: a #GtkTreeViewColumn
1927 * Returns %TRUE if the user can click on the header for the column.
1929 * Return value: %TRUE if user can click the column header.
1932 gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
1934 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
1936 return tree_column->clickable;
1940 * gtk_tree_view_column_set_widget:
1941 * @tree_column: A #GtkTreeViewColumn.
1942 * @widget: A child #GtkWidget, or %NULL.
1944 * Sets the widget in the header to be @widget. If widget is %NULL, then the
1945 * header button is set with a #GtkLabel set to the title of @tree_column.
1948 gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
1951 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
1952 g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
1956 gtk_object_ref (GTK_OBJECT (widget));
1957 gtk_object_sink (GTK_OBJECT (widget));
1960 if (tree_column->child)
1961 gtk_object_unref (GTK_OBJECT (tree_column->child));
1963 tree_column->child = widget;
1964 gtk_tree_view_column_update_button (tree_column);
1965 g_object_notify (G_OBJECT (tree_column), "widget");
1969 * gtk_tree_view_column_get_widget:
1970 * @tree_column: A #GtkTreeViewColumn.
1972 * Returns the #GtkWidget in the button on the column header. If a custom
1973 * widget has not been set then %NULL is returned.
1975 * Return value: The #GtkWidget in the column header, or %NULL
1978 gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
1980 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
1982 return tree_column->child;
1986 * gtk_tree_view_column_set_alignment:
1987 * @tree_column: A #GtkTreeViewColumn.
1988 * @xalign: The alignment, which is between [0.0 and 1.0] inclusive.
1990 * Sets the alignment of the title or custom widget inside the column header.
1991 * The alignment determines its location inside the button -- 0.0 for left, 0.5
1992 * for center, 1.0 for right.
1995 gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
1998 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2000 xalign = CLAMP (xalign, 0.0, 1.0);
2002 if (tree_column->xalign == xalign)
2005 tree_column->xalign = xalign;
2006 gtk_tree_view_column_update_button (tree_column);
2007 g_object_notify (G_OBJECT (tree_column), "alignment");
2011 * gtk_tree_view_column_get_alignment:
2012 * @tree_column: A #GtkTreeViewColumn.
2014 * Returns the current x alignment of @tree_column. This value can range
2015 * between 0.0 and 1.0.
2017 * Return value: The current alignent of @tree_column.
2020 gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
2022 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0.5);
2024 return tree_column->xalign;
2028 * gtk_tree_view_column_set_reorderable:
2029 * @tree_column: A #GtkTreeViewColumn
2030 * @reorderable: #TRUE, if the column can be reordered.
2032 * If @reorderable is #TRUE, then the column can be reordered by the end user
2033 * dragging the header.
2036 gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
2037 gboolean reorderable)
2039 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2042 gtk_tree_view_column_set_clickable (tree_column, TRUE);*/
2044 if (tree_column->reorderable == (reorderable?TRUE:FALSE))
2047 tree_column->reorderable = (reorderable?TRUE:FALSE);
2048 gtk_tree_view_column_update_button (tree_column);
2049 g_object_notify (G_OBJECT (tree_column), "reorderable");
2053 * gtk_tree_view_column_get_reorderable:
2054 * @tree_column: A #GtkTreeViewColumn
2056 * Returns #TRUE if the @tree_column can be reordered by the user.
2058 * Return value: #TRUE if the @tree_column can be reordered by the user.
2061 gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
2063 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2065 return tree_column->reorderable;
2070 * gtk_tree_view_column_set_sort_column_id:
2071 * @tree_column: a #GtkTreeViewColumn
2072 * @sort_column_id: The @sort_column_id of the model to sort on.
2074 * Sets the logical @sort_column_id that this column sorts on when this column
2075 * is selected for sorting. Doing so makes the column header clickable.
2078 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
2079 gint sort_column_id)
2081 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2082 g_return_if_fail (sort_column_id >= 0);
2084 if (tree_column->sort_column_id == sort_column_id)
2087 tree_column->sort_column_id = sort_column_id;
2089 /* Handle unsetting the id */
2090 if (sort_column_id == -1)
2092 if (tree_column->sort_clicked_signal)
2094 g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
2095 tree_column->sort_clicked_signal = 0;
2098 if (tree_column->sort_column_changed_signal)
2100 g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
2101 tree_column->sort_column_changed_signal = 0;
2104 gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
2105 gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
2109 gtk_tree_view_column_set_clickable (tree_column, TRUE);
2111 if (! tree_column->sort_clicked_signal)
2112 tree_column->sort_clicked_signal = g_signal_connect (G_OBJECT (tree_column),
2114 G_CALLBACK (gtk_tree_view_column_sort),
2117 gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
2121 * gtk_tree_view_column_get_sort_column_id:
2122 * @tree_column: a #GtkTreeViewColumn
2124 * Gets the logical @sort_column_id that the model sorts on when this
2125 * column is selected for sorting. See gtk_tree_view_column_set_sort_column_id().
2127 * Return value: the current @sort_column_id for this column, or -1 if
2128 * this column can't be used for sorting.
2131 gtk_tree_view_column_get_sort_column_id (GtkTreeViewColumn *tree_column)
2133 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2135 return tree_column->sort_column_id;
2139 * gtk_tree_view_column_set_sort_indicator:
2140 * @tree_column: a #GtkTreeViewColumn
2141 * @setting: %TRUE to display an indicator that the column is sorted
2143 * Call this function with a @setting of %TRUE to display an arrow in
2144 * the header button indicating the column is sorted. Call
2145 * gtk_tree_view_column_set_sort_order() to change the direction of
2150 gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn *tree_column,
2153 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2155 setting = setting != FALSE;
2157 if (setting == tree_column->show_sort_indicator)
2160 tree_column->show_sort_indicator = setting;
2161 gtk_tree_view_column_update_button (tree_column);
2162 g_object_notify (G_OBJECT (tree_column), "sort_indicator");
2166 * gtk_tree_view_column_get_sort_indicator:
2167 * @tree_column: a #GtkTreeViewColumn
2169 * Gets the value set by gtk_tree_view_column_set_sort_indicator().
2171 * Return value: whether the sort indicator arrow is displayed
2174 gtk_tree_view_column_get_sort_indicator (GtkTreeViewColumn *tree_column)
2176 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2178 return tree_column->show_sort_indicator;
2182 * gtk_tree_view_column_set_sort_order:
2183 * @tree_column: a #GtkTreeViewColumn
2184 * @order: sort order that the sort indicator should indicate
2186 * Changes the appearance of the sort indicator.
2188 * This <emphasis>does not</emphasis> actually sort the model. Use
2189 * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
2190 * support. This function is primarily for custom sorting behavior, and should
2191 * be used in conjunction with gtk_tree_sortable_set_sort_column() to do
2192 * that. For custom models, the mechanism will vary.
2194 * The sort indicator changes direction to indicate normal sort or reverse sort.
2195 * Note that you must have the sort indicator enabled to see anything when
2196 * calling this function; see gtk_tree_view_column_set_sort_indicator().
2199 gtk_tree_view_column_set_sort_order (GtkTreeViewColumn *tree_column,
2202 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2204 if (order == tree_column->sort_order)
2207 tree_column->sort_order = order;
2208 gtk_tree_view_column_update_button (tree_column);
2209 g_object_notify (G_OBJECT (tree_column), "sort_order");
2213 * gtk_tree_view_column_get_sort_order:
2214 * @tree_column: a #GtkTreeViewColumn
2216 * Gets the value set by gtk_tree_view_column_set_sort_order().
2218 * Return value: the sort order the sort indicator is indicating
2221 gtk_tree_view_column_get_sort_order (GtkTreeViewColumn *tree_column)
2223 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), 0);
2225 return tree_column->sort_order;
2229 * gtk_tree_view_column_cell_set_cell_data:
2230 * @tree_column: A #GtkTreeViewColumn.
2231 * @tree_model: The #GtkTreeModel to to get the cell renderers attributes from.
2232 * @iter: The #GtkTreeIter to to get the cell renderer's attributes from.
2233 * @is_expander: %TRUE, if the row has children
2234 * @is_expanded: %TRUE, if the row has visible children
2236 * Sets the cell renderer based on the @tree_model and @tree_node. That is, for
2237 * every attribute mapping in @tree_column, it will get a value from the set
2238 * column on the @tree_node, and use that value to set the attribute on the cell
2239 * renderer. This is used primarily by the #GtkTreeView.
2242 gtk_tree_view_column_cell_set_cell_data (GtkTreeViewColumn *tree_column,
2243 GtkTreeModel *tree_model,
2245 gboolean is_expander,
2246 gboolean is_expanded)
2249 GValue value = { 0, };
2252 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2253 g_return_if_fail (tree_column->cell_list != NULL);
2255 if (tree_model == NULL)
2258 for (cell_list = tree_column->cell_list; cell_list; cell_list = cell_list->next)
2260 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) cell_list->data;
2261 GObject *cell = (GObject *) info->cell;
2263 list = info->attributes;
2265 g_object_freeze_notify (cell);
2266 g_object_set (cell, "is_expander", is_expander, "is_expanded", is_expanded, NULL);
2268 while (list && list->next)
2270 gtk_tree_model_get_value (tree_model, iter,
2271 GPOINTER_TO_INT (list->next->data),
2273 g_object_set_property (cell, (gchar *) list->data, &value);
2274 g_value_unset (&value);
2275 list = list->next->next;
2279 (* info->func) (tree_column, info->cell, tree_model, iter, info->func_data);
2280 g_object_thaw_notify (G_OBJECT (info->cell));
2286 * gtk_tree_view_column_cell_get_size:
2287 * @tree_column: A #GtkTreeViewColumn.
2288 * @cell_area: The area a the column will be allocated, or %NULL
2289 * @x_offset: location to return x offset of cell relative to @cell_area, or %NULL
2290 * @y_offset: location to return y offset of cell relative to @cell_area, or %NULL
2291 * @width: location to return width needed to render a cell, or %NULL
2292 * @height: location to return height needed to render a cell, or %NULL
2294 * Obtains the width and height needed to render the column. This is used
2295 * primarily by the #GtkTreeView.
2298 gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
2299 GdkRectangle *cell_area,
2306 gboolean first_cell = TRUE;
2307 gint focus_line_width;
2309 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2316 gtk_widget_style_get (tree_column->tree_view, "focus-line-width", &focus_line_width, NULL);
2318 for (list = tree_column->cell_list; list; list = list->next)
2320 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2322 gint new_height = 0;
2324 g_object_get (info->cell, "visible", &visible, NULL);
2326 if (visible == FALSE)
2329 if (first_cell == FALSE && *width)
2330 *width += tree_column->spacing;
2332 gtk_cell_renderer_get_size (info->cell,
2333 tree_column->tree_view,
2341 * height = MAX (*height, new_height + focus_line_width * 2);
2342 info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
2344 * width += info->requested_width;
2349 /* both rendering and rendering focus are somewhat complicated, and a bit of
2350 * code. Rather than duplicate them, we put them together to keep the code in
2360 gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column,
2362 GdkRectangle *background_area,
2363 GdkRectangle *cell_area,
2366 GdkRectangle *expose_area, /* RENDER */
2367 GdkRectangle *focus_rectangle, /* FOCUS */
2368 GtkCellEditable **editable_widget, /* EVENT */
2369 GdkEvent *event, /* EVENT */
2370 gchar *path_string) /* EVENT */
2373 GdkRectangle real_cell_area;
2374 GdkRectangle real_background_area;
2375 gint expand_cell_count = 0;
2376 gint full_requested_width = 0;
2378 gint min_x, min_y, max_x, max_y;
2379 gint focus_line_width;
2388 special_cells = _gtk_tree_view_column_count_special_cells (tree_column);
2390 if (special_cells > 1 && action == CELL_ACTION_FOCUS)
2392 GtkTreeViewColumnCellInfo *info = NULL;
2393 gboolean found_has_focus = FALSE;
2395 /* one should have focus */
2396 for (list = tree_column->cell_list; list; list = list->next)
2399 if (info && info->has_focus)
2401 found_has_focus = TRUE;
2406 if (!found_has_focus)
2408 /* give the first one focus */
2409 info = gtk_tree_view_column_cell_first (tree_column)->data;
2410 info->has_focus = TRUE;
2414 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
2415 "focus-line-width", &focus_line_width,
2418 real_cell_area = *cell_area;
2419 real_background_area = *background_area;
2420 dx = real_cell_area.x - real_background_area.x - focus_line_width;
2422 real_cell_area.x += focus_line_width;
2424 /* Find out how many extra space we have to allocate */
2425 for (list = tree_column->cell_list; list; list = list->next)
2427 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
2429 if (! info->cell->visible)
2432 if (info->expand == TRUE)
2433 expand_cell_count ++;
2434 full_requested_width += info->requested_width;
2437 extra_space = background_area->width - full_requested_width;
2438 if (extra_space < 0)
2440 else if (extra_space > 0 && expand_cell_count > 0)
2441 extra_space /= expand_cell_count;
2443 /* iterate list for GTK_PACK_START cells */
2444 for (list = tree_column->cell_list; list; list = list->next)
2446 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2448 if (info->pack == GTK_PACK_END)
2451 if (! info->cell->visible)
2454 real_background_area.width = info->requested_width +
2455 (info->expand?extra_space:0);
2456 info->real_width = real_background_area.width;
2458 real_cell_area.width = real_background_area.width;
2459 real_cell_area.width -= 2 * focus_line_width;
2461 if (action == CELL_ACTION_RENDER)
2463 gtk_cell_renderer_render (info->cell,
2465 tree_column->tree_view,
2466 &real_background_area,
2471 else if (action == CELL_ACTION_FOCUS)
2473 gint x_offset, y_offset, width, height;
2475 gtk_cell_renderer_get_size (info->cell,
2476 tree_column->tree_view,
2478 &x_offset, &y_offset,
2481 if (special_cells > 1)
2483 if (info->has_focus)
2485 min_x = real_cell_area.x + x_offset;
2486 max_x = min_x + width;
2487 min_y = real_cell_area.y + y_offset;
2488 max_y = min_y + height;
2493 if (min_x > (real_cell_area.x + x_offset))
2494 min_x = real_cell_area.x + x_offset;
2495 if (max_x < real_cell_area.x + x_offset + width)
2496 max_x = real_cell_area.x + x_offset + width;
2497 if (min_y > (real_cell_area.y + y_offset))
2498 min_y = real_cell_area.y + y_offset;
2499 if (max_y < real_cell_area.y + y_offset + height)
2500 max_y = real_cell_area.y + y_offset + height;
2503 else if (action == CELL_ACTION_EVENT)
2505 gboolean try_event = FALSE;
2509 if (special_cells == 1)
2511 /* only 1 activatable cell -> whole column can activate */
2512 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2513 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2516 else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2517 real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2518 /* only activate cell if the user clicked on an individual
2523 else if (special_cells > 1 && info->has_focus)
2525 else if (special_cells == 1)
2530 gboolean visible, mode;
2532 g_object_get (G_OBJECT (info->cell),
2533 "visible", &visible,
2536 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2538 if (gtk_cell_renderer_activate (info->cell,
2540 tree_column->tree_view,
2547 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2550 gtk_cell_renderer_start_editing (info->cell,
2552 tree_column->tree_view,
2558 if (*editable_widget != NULL)
2560 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2561 info->in_editing_mode = TRUE;
2562 gtk_tree_view_column_focus_cell (tree_column, info->cell);
2570 real_cell_area.x += (info->real_width + tree_column->spacing);
2571 real_background_area.x += (info->real_width + tree_column->spacing);
2574 /* iterate list for PACK_END cells */
2575 for (list = g_list_last (tree_column->cell_list); list; list = list->prev)
2577 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
2579 if (info->pack == GTK_PACK_START)
2582 if (! info->cell->visible)
2585 real_background_area.width = info->requested_width +
2586 (info->expand?extra_space:0);
2587 info->real_width = real_background_area.width;
2589 real_cell_area.width = real_background_area.width;
2590 real_cell_area.width -= 2 * focus_line_width;
2592 if (action == CELL_ACTION_RENDER)
2594 gtk_cell_renderer_render (info->cell,
2596 tree_column->tree_view,
2597 &real_background_area,
2602 else if (action == CELL_ACTION_FOCUS)
2604 gint x_offset, y_offset, width, height;
2606 gtk_cell_renderer_get_size (info->cell,
2607 tree_column->tree_view,
2609 &x_offset, &y_offset,
2612 if (special_cells > 1)
2614 if (info->has_focus)
2616 min_x = real_cell_area.x + x_offset;
2617 max_x = min_x + width;
2618 min_y = real_cell_area.y + y_offset;
2619 max_y = min_y + height;
2624 if (min_x > (real_cell_area.x + x_offset))
2625 min_x = real_cell_area.x + x_offset;
2626 if (max_x < real_cell_area.x + x_offset + width)
2627 max_x = real_cell_area.x + x_offset + width;
2628 if (min_y > (real_cell_area.y + y_offset))
2629 min_y = real_cell_area.y + y_offset;
2630 if (max_y < real_cell_area.y + y_offset + height)
2631 max_y = real_cell_area.y + y_offset + height;
2634 else if (action == CELL_ACTION_EVENT)
2636 gboolean try_event = FALSE;
2640 if (special_cells == 1)
2642 /* only 1 activatable cell -> whole column can activate */
2643 if (cell_area->x <= ((GdkEventButton *)event)->x &&
2644 cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
2647 else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
2648 real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
2649 /* only activate cell if the user clicked on an individual
2654 else if (special_cells > 1 && info->has_focus)
2656 else if (special_cells == 1)
2661 gboolean visible, mode;
2663 g_object_get (G_OBJECT (info->cell),
2664 "visible", &visible,
2667 if (visible && mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
2669 if (gtk_cell_renderer_activate (info->cell,
2671 tree_column->tree_view,
2678 else if (visible && mode == GTK_CELL_RENDERER_MODE_EDITABLE)
2681 gtk_cell_renderer_start_editing (info->cell,
2683 tree_column->tree_view,
2689 if (*editable_widget != NULL)
2691 g_return_val_if_fail (GTK_IS_CELL_EDITABLE (*editable_widget), FALSE);
2692 info->in_editing_mode = TRUE;
2693 gtk_tree_view_column_focus_cell (tree_column, info->cell);
2701 real_cell_area.x += (info->real_width + tree_column->spacing);
2702 real_background_area.x += (info->real_width + tree_column->spacing);
2705 /* fill focus_rectangle when required */
2706 if (action == CELL_ACTION_FOCUS)
2708 if (min_x >= max_x || min_y >= max_y)
2710 *focus_rectangle = *cell_area;
2711 /* don't change the focus_rectangle, just draw it nicely inside
2716 focus_rectangle->x = min_x - focus_line_width;
2717 focus_rectangle->y = min_y - focus_line_width;
2718 focus_rectangle->width = (max_x - min_x) + 2 * focus_line_width;
2719 focus_rectangle->height = (max_y - min_y) + 2 * focus_line_width;
2727 * gtk_tree_view_column_cell_render:
2728 * @tree_column: A #GtkTreeViewColumn.
2729 * @window: a #GdkDrawable to draw to
2730 * @background_area: entire cell area (including tree expanders and maybe padding on the sides)
2731 * @cell_area: area normally rendered by a cell renderer
2732 * @expose_area: area that actually needs updating
2733 * @flags: flags that affect rendering
2735 * Renders the cell contained by #tree_column. This is used primarily by the
2739 _gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
2741 GdkRectangle *background_area,
2742 GdkRectangle *cell_area,
2743 GdkRectangle *expose_area,
2746 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
2747 g_return_if_fail (background_area != NULL);
2748 g_return_if_fail (cell_area != NULL);
2749 g_return_if_fail (expose_area != NULL);
2751 gtk_tree_view_column_cell_process_action (tree_column,
2758 NULL, NULL, NULL, NULL);
2762 _gtk_tree_view_column_cell_event (GtkTreeViewColumn *tree_column,
2763 GtkCellEditable **editable_widget,
2766 GdkRectangle *background_area,
2767 GdkRectangle *cell_area,
2770 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
2772 return gtk_tree_view_column_cell_process_action (tree_column,
2784 /* cell list manipulation */
2786 gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column)
2788 GList *list = tree_column->cell_list;
2790 /* first GTK_PACK_START cell we find */
2791 for ( ; list; list = list->next)
2793 GtkTreeViewColumnCellInfo *info = list->data;
2794 if (info->pack == GTK_PACK_START)
2798 /* hmm, else the *last* GTK_PACK_END cell */
2799 list = g_list_last (tree_column->cell_list);
2801 for ( ; list; list = list->prev)
2803 GtkTreeViewColumnCellInfo *info = list->data;
2804 if (info->pack == GTK_PACK_END)
2812 gtk_tree_view_column_cell_last (GtkTreeViewColumn *tree_column)
2814 GList *list = tree_column->cell_list;
2816 /* *first* GTK_PACK_END cell we find */
2817 for ( ; list ; list = list->next)
2819 GtkTreeViewColumnCellInfo *info = list->data;
2820 if (info->pack == GTK_PACK_END)
2824 /* hmm, else the last GTK_PACK_START cell */
2825 list = g_list_last (tree_column->cell_list);
2827 for ( ; list; list = list->prev)
2829 GtkTreeViewColumnCellInfo *info = list->data;
2830 if (info->pack == GTK_PACK_START)
2838 gtk_tree_view_column_cell_next (GtkTreeViewColumn *tree_column,
2842 GtkTreeViewColumnCellInfo *info = current->data;
2844 if (info->pack == GTK_PACK_START)
2846 for (list = current->next; list; list = list->next)
2848 GtkTreeViewColumnCellInfo *inf = list->data;
2849 if (inf->pack == GTK_PACK_START)
2853 /* out of GTK_PACK_START cells, get *last* GTK_PACK_END one */
2854 list = g_list_last (tree_column->cell_list);
2855 for (; list; list = list->prev)
2857 GtkTreeViewColumnCellInfo *inf = list->data;
2858 if (inf->pack == GTK_PACK_END)
2863 for (list = current->prev; list; list = list->prev)
2865 GtkTreeViewColumnCellInfo *inf = list->data;
2866 if (inf->pack == GTK_PACK_END)
2874 gtk_tree_view_column_cell_prev (GtkTreeViewColumn *tree_column,
2878 GtkTreeViewColumnCellInfo *info = current->data;
2880 if (info->pack == GTK_PACK_END)
2882 for (list = current->next; list; list = list->next)
2884 GtkTreeViewColumnCellInfo *inf = list->data;
2885 if (inf->pack == GTK_PACK_END)
2889 /* out of GTK_PACK_END, get last GTK_PACK_START one */
2890 list = g_list_last (tree_column->cell_list);
2891 for ( ; list; list = list->prev)
2893 GtkTreeViewColumnCellInfo *inf = list->data;
2894 if (inf->pack == GTK_PACK_START)
2899 for (list = current->prev; list; list = list->prev)
2901 GtkTreeViewColumnCellInfo *inf = list->data;
2902 if (inf->pack == GTK_PACK_START)
2910 _gtk_tree_view_column_cell_focus (GtkTreeViewColumn *tree_column,
2917 count = _gtk_tree_view_column_count_special_cells (tree_column);
2919 /* if we are the current focus column and have multiple editable cells,
2920 * try to select the next one, else move the focus to the next column
2922 if (GTK_TREE_VIEW (tree_column->tree_view)->priv->focus_column == tree_column)
2927 GList *list = tree_column->cell_list;
2928 GtkTreeViewColumnCellInfo *info = NULL;
2930 /* find current focussed cell */
2931 for ( ; list; list = list->next)
2934 if (info->has_focus)
2938 /* not a focussed cell in the focus column? */
2939 if (!list || !info || !info->has_focus)
2942 next = gtk_tree_view_column_cell_next (tree_column, list);
2943 prev = gtk_tree_view_column_cell_prev (tree_column, list);
2945 info->has_focus = FALSE;
2946 if (direction > 0 && next)
2949 info->has_focus = TRUE;
2952 else if (direction > 0 && !next && !right)
2954 /* keep focus on latest cell */
2955 info = gtk_tree_view_column_cell_last (tree_column)->data;
2956 info->has_focus = TRUE;
2959 else if (direction < 0 && prev)
2962 info->has_focus = TRUE;
2965 else if (direction < 0 && !prev && !left)
2967 /* keep focus on first cell */
2968 info = gtk_tree_view_column_cell_first (tree_column)->data;
2969 info->has_focus = TRUE;
2976 /* we get focus, if we have multiple editable cells, give the correct one
2981 GList *list = tree_column->cell_list;
2983 /* clear focus first */
2984 for ( ; list ; list = list->next)
2986 GtkTreeViewColumnCellInfo *info = list->data;
2987 if (info->has_focus)
2988 info->has_focus = FALSE;
2992 ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_first (tree_column)->data)->has_focus = TRUE;
2993 else if (direction < 0)
2994 ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_last (tree_column)->data)->has_focus = TRUE;
3000 _gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column,
3002 GdkRectangle *background_area,
3003 GdkRectangle *cell_area,
3004 GdkRectangle *expose_area,
3007 gint focus_line_width;
3008 GtkStateType cell_state;
3010 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3011 gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
3012 "focus-line-width", &focus_line_width, NULL);
3013 if (tree_column->editable_widget)
3015 /* This function is only called on the editable row when editing.
3018 gtk_paint_focus (tree_column->tree_view->style,
3020 GTK_WIDGET_STATE (tree_column->tree_view),
3022 tree_column->tree_view,
3024 cell_area->x - focus_line_width,
3025 cell_area->y - focus_line_width,
3026 cell_area->width + 2 * focus_line_width,
3027 cell_area->height + 2 * focus_line_width);
3032 GdkRectangle focus_rectangle;
3033 gtk_tree_view_column_cell_process_action (tree_column,
3043 cell_state = flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
3044 (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
3045 (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
3046 gtk_paint_focus (tree_column->tree_view->style,
3050 tree_column->tree_view,
3054 focus_rectangle.width,
3055 focus_rectangle.height);
3060 * gtk_tree_view_column_cell_is_visible:
3061 * @tree_column: A #GtkTreeViewColumn
3063 * Returns #TRUE if any of the cells packed into the @tree_column are visible.
3064 * For this to be meaningful, you must first initialize the cells with
3065 * gtk_tree_view_column_cell_set_cell_data()
3067 * Return value: #TRUE, if any of the cells packed into the @tree_column are currently visible
3070 gtk_tree_view_column_cell_is_visible (GtkTreeViewColumn *tree_column)
3074 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
3076 for (list = tree_column->cell_list; list; list = list->next)
3078 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3080 if (info->cell->visible)
3088 * gtk_tree_view_column_focus_cell:
3089 * @tree_view: A #GtkTreeView
3090 * @cell: A #GtkCellRenderer
3092 * Sets the current keyboard focus to be at @cell, if the column contains
3093 * 2 or more editable and activatable cells.
3096 gtk_tree_view_column_focus_cell (GtkTreeViewColumn *tree_column,
3097 GtkCellRenderer *cell)
3100 gboolean found_cell = FALSE;
3102 g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
3103 g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
3105 if (_gtk_tree_view_column_count_special_cells (tree_column) < 2)
3108 for (list = tree_column->cell_list; list; list = list->next)
3110 GtkTreeViewColumnCellInfo *info = list->data;
3112 if (info->cell == cell)
3114 info->has_focus = TRUE;
3122 for (list = tree_column->cell_list; list; list = list->next)
3124 GtkTreeViewColumnCellInfo *info = list->data;
3126 if (info->cell != cell)
3127 info->has_focus = FALSE;
3130 /* FIXME: redraw? */
3135 _gtk_tree_view_column_cell_set_dirty (GtkTreeViewColumn *tree_column,
3136 gboolean install_handler)
3140 for (list = tree_column->cell_list; list; list = list->next)
3142 GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
3144 info->requested_width = 0;
3146 tree_column->dirty = TRUE;
3147 tree_column->resized_width = MAX (tree_column->requested_width, tree_column->button_request);
3148 tree_column->requested_width = -1;
3149 tree_column->width = 0;
3151 if (tree_column->tree_view &&
3152 GTK_WIDGET_REALIZED (tree_column->tree_view))
3154 if (install_handler)
3155 _gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
3157 GTK_TREE_VIEW (tree_column->tree_view)->priv->mark_rows_col_dirty = TRUE;
3158 gtk_widget_queue_resize (tree_column->tree_view);
3163 _gtk_tree_view_column_start_editing (GtkTreeViewColumn *tree_column,
3164 GtkCellEditable *cell_editable)
3166 g_return_if_fail (tree_column->editable_widget == NULL);
3168 tree_column->editable_widget = cell_editable;
3172 _gtk_tree_view_column_stop_editing (GtkTreeViewColumn *tree_column)
3176 g_return_if_fail (tree_column->editable_widget != NULL);
3178 tree_column->editable_widget = NULL;
3179 for (list = tree_column->cell_list; list; list = list->next)
3180 ((GtkTreeViewColumnCellInfo *)list->data)->in_editing_mode = FALSE;
3184 _gtk_tree_view_column_get_neighbor_sizes (GtkTreeViewColumn *column,
3185 GtkCellRenderer *cell,
3194 list = gtk_tree_view_column_cell_first (column);
3196 for (; list; list = gtk_tree_view_column_cell_next (column, list))
3198 GtkTreeViewColumnCellInfo *info =
3199 (GtkTreeViewColumnCellInfo *)list->data;
3201 if (info->cell == cell)
3204 *left += info->real_width;
3213 list = gtk_tree_view_column_cell_first (column);
3215 for (; list; list = gtk_tree_view_column_cell_next (column, list))
3217 GtkTreeViewColumnCellInfo *info =
3218 (GtkTreeViewColumnCellInfo *)list->data;
3220 if (info->cell == cell)
3225 next = gtk_tree_view_column_cell_next (column, list);
3229 for ( ; list; list = gtk_tree_view_column_cell_next (column, list))
3231 GtkTreeViewColumnCellInfo *info =
3232 (GtkTreeViewColumnCellInfo *)list->data;
3234 *right += info->real_width;