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.
21 #include "gtktreeview.h"
22 #include "gtkrbtree.h"
23 #include "gtktreeprivate.h"
24 #include "gtkcellrenderer.h"
25 #include "gtksignal.h"
27 #include "gtkbutton.h"
28 #include "gtkalignment.h"
31 #include <gdk/gdkkeysyms.h>
34 /* the width of the column resize windows */
35 #define TREE_VIEW_DRAG_WIDTH 6
36 #define TREE_VIEW_EXPANDER_WIDTH 14
37 #define TREE_VIEW_EXPANDER_HEIGHT 14
38 #define TREE_VIEW_VERTICAL_SEPERATOR 2
39 #define TREE_VIEW_HORIZONTAL_SEPERATOR 0
42 typedef struct _GtkTreeViewChild GtkTreeViewChild;
44 struct _GtkTreeViewChild
52 static void gtk_tree_view_init (GtkTreeView *tree_view);
53 static void gtk_tree_view_class_init (GtkTreeViewClass *klass);
56 static void gtk_tree_view_set_model_realized (GtkTreeView *tree_view);
57 static void gtk_tree_view_realize (GtkWidget *widget);
58 static void gtk_tree_view_unrealize (GtkWidget *widget);
59 static void gtk_tree_view_map (GtkWidget *widget);
60 static void gtk_tree_view_size_request (GtkWidget *widget,
61 GtkRequisition *requisition);
62 static void gtk_tree_view_size_allocate (GtkWidget *widget,
63 GtkAllocation *allocation);
64 static void gtk_tree_view_draw (GtkWidget *widget,
66 static gboolean gtk_tree_view_expose (GtkWidget *widget,
67 GdkEventExpose *event);
68 static gboolean gtk_tree_view_motion (GtkWidget *widget,
69 GdkEventMotion *event);
70 static gboolean gtk_tree_view_enter_notify (GtkWidget *widget,
71 GdkEventCrossing *event);
72 static gboolean gtk_tree_view_leave_notify (GtkWidget *widget,
73 GdkEventCrossing *event);
74 static gboolean gtk_tree_view_button_press (GtkWidget *widget,
75 GdkEventButton *event);
76 static gboolean gtk_tree_view_button_release (GtkWidget *widget,
77 GdkEventButton *event);
78 static void gtk_tree_view_draw_focus (GtkWidget *widget);
79 static gint gtk_tree_view_focus_in (GtkWidget *widget,
80 GdkEventFocus *event);
81 static gint gtk_tree_view_focus_out (GtkWidget *widget,
82 GdkEventFocus *event);
83 static gint gtk_tree_view_focus (GtkContainer *container,
84 GtkDirectionType direction);
86 /* container signals */
87 static void gtk_tree_view_remove (GtkContainer *container,
89 static void gtk_tree_view_forall (GtkContainer *container,
90 gboolean include_internals,
92 gpointer callback_data);
94 /* tree_model signals */
95 static void gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
98 static void gtk_tree_view_node_changed (GtkTreeModel *model,
100 GtkTreeNode tree_node,
102 static void gtk_tree_view_node_inserted (GtkTreeModel *model,
104 GtkTreeNode tree_node,
106 static void gtk_tree_view_node_child_toggled (GtkTreeModel *model,
108 GtkTreeNode tree_node,
110 static void gtk_tree_view_node_deleted (GtkTreeModel *model,
114 /* Internal functions */
115 static void gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
120 static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view,
123 static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
124 GtkTreeView *tree_view);
125 static gint gtk_tree_view_insert_node_height (GtkTreeView *tree_view,
129 static void gtk_tree_view_build_tree (GtkTreeView *tree_view,
134 gboolean calc_bounds);
135 static void gtk_tree_view_calc_size (GtkTreeView *priv,
139 static gboolean gtk_tree_view_discover_dirty_node (GtkTreeView *tree_view,
143 static void gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
147 static void gtk_tree_view_check_dirty (GtkTreeView *tree_view);
148 static void gtk_tree_view_create_button (GtkTreeView *tree_view,
150 static void gtk_tree_view_create_buttons (GtkTreeView *tree_view);
151 static void gtk_tree_view_button_clicked (GtkWidget *widget,
153 static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
159 static GtkContainerClass *parent_class = NULL;
162 /* Class Functions */
164 gtk_tree_view_get_type (void)
166 static GtkType tree_view_type = 0;
170 static const GTypeInfo tree_view_info =
172 sizeof (GtkTreeViewClass),
173 NULL, /* base_init */
174 NULL, /* base_finalize */
175 (GClassInitFunc) gtk_tree_view_class_init,
176 NULL, /* class_finalize */
177 NULL, /* class_data */
178 sizeof (GtkTreeView),
180 (GInstanceInitFunc) gtk_tree_view_init
183 tree_view_type = g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView", &tree_view_info);
186 return tree_view_type;
190 gtk_tree_view_class_init (GtkTreeViewClass *class)
192 GtkObjectClass *object_class;
193 GtkWidgetClass *widget_class;
194 GtkContainerClass *container_class;
196 object_class = (GtkObjectClass*) class;
197 widget_class = (GtkWidgetClass*) class;
198 container_class = (GtkContainerClass*) class;
199 parent_class = g_type_class_peek_parent (class);
201 widget_class->realize = gtk_tree_view_realize;
202 widget_class->unrealize = gtk_tree_view_unrealize;
203 widget_class->map = gtk_tree_view_map;
204 widget_class->size_request = gtk_tree_view_size_request;
205 widget_class->size_allocate = gtk_tree_view_size_allocate;
206 widget_class->draw = gtk_tree_view_draw;
207 widget_class->expose_event = gtk_tree_view_expose;
208 // widget_class->key_press_event = gtk_tree_view_key_press;
209 widget_class->motion_notify_event = gtk_tree_view_motion;
210 widget_class->enter_notify_event = gtk_tree_view_enter_notify;
211 widget_class->leave_notify_event = gtk_tree_view_leave_notify;
212 widget_class->button_press_event = gtk_tree_view_button_press;
213 widget_class->button_release_event = gtk_tree_view_button_release;
214 widget_class->draw_focus = gtk_tree_view_draw_focus;
215 widget_class->focus_in_event = gtk_tree_view_focus_in;
216 widget_class->focus_out_event = gtk_tree_view_focus_out;
218 container_class->forall = gtk_tree_view_forall;
219 container_class->remove = gtk_tree_view_remove;
220 container_class->focus = gtk_tree_view_focus;
222 class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
224 widget_class->set_scroll_adjustments_signal =
225 gtk_signal_new ("set_scroll_adjustments",
227 GTK_CLASS_TYPE (object_class),
228 GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
229 gtk_marshal_NONE__POINTER_POINTER,
231 GTK_TYPE_POINTER, GTK_TYPE_POINTER);
235 gtk_tree_view_init (GtkTreeView *tree_view)
237 tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
239 GTK_WIDGET_UNSET_FLAGS (tree_view, GTK_NO_WINDOW);
240 GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
242 tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
243 tree_view->priv->tab_offset = TREE_VIEW_EXPANDER_WIDTH;
244 tree_view->priv->columns = 0;
245 tree_view->priv->column = NULL;
246 tree_view->priv->button_pressed_node = NULL;
247 tree_view->priv->button_pressed_tree = NULL;
248 tree_view->priv->prelight_node = NULL;
249 tree_view->priv->prelight_offset = 0;
250 tree_view->priv->header_height = 1;
251 tree_view->priv->x_drag = 0;
252 tree_view->priv->drag_pos = -1;
253 tree_view->priv->selection = NULL;
254 tree_view->priv->anchor = NULL;
255 tree_view->priv->cursor = NULL;
256 gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
257 _gtk_tree_view_set_size (tree_view, 0, 0);
264 gtk_tree_view_realize_buttons (GtkTreeView *tree_view)
267 GtkTreeViewColumn *column;
269 guint attributes_mask;
271 if (!GTK_WIDGET_REALIZED (tree_view) || tree_view->priv->header_window == NULL)
274 attr.window_type = GDK_WINDOW_CHILD;
275 attr.wclass = GDK_INPUT_ONLY;
276 attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
277 attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
278 attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view));
279 attr.event_mask = (GDK_BUTTON_PRESS_MASK |
280 GDK_BUTTON_RELEASE_MASK |
281 GDK_POINTER_MOTION_MASK |
282 GDK_POINTER_MOTION_HINT_MASK |
284 attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
285 attr.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW);
286 tree_view->priv->cursor_drag = attr.cursor;
289 attr.width = TREE_VIEW_DRAG_WIDTH;
290 attr.height = tree_view->priv->header_height;
292 for (list = tree_view->priv->column; list; list = list->next)
297 if (column->visible == FALSE)
299 gtk_widget_set_parent_window (column->button,
300 tree_view->priv->header_window);
301 gtk_widget_show (column->button);
303 attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
305 column->window = gdk_window_new (tree_view->priv->header_window,
306 &attr, attributes_mask);
307 gdk_window_set_user_data (column->window, tree_view);
313 gtk_tree_view_realize (GtkWidget *widget)
316 GtkTreeView *tree_view;
318 GdkWindowAttr attributes;
319 gint attributes_mask;
321 g_return_if_fail (widget != NULL);
322 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
324 tree_view = GTK_TREE_VIEW (widget);
326 if (!GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP) &&
327 tree_view->priv->model)
328 gtk_tree_view_set_model_realized (tree_view);
330 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
331 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
333 /* Make the main, clipping window */
334 attributes.window_type = GDK_WINDOW_CHILD;
335 attributes.x = widget->allocation.x;
336 attributes.y = widget->allocation.y;
337 attributes.width = widget->allocation.width;
338 attributes.height = widget->allocation.height;
339 attributes.wclass = GDK_INPUT_OUTPUT;
340 attributes.visual = gtk_widget_get_visual (widget);
341 attributes.colormap = gtk_widget_get_colormap (widget);
342 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
344 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
346 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
347 &attributes, attributes_mask);
348 gdk_window_set_user_data (widget->window, widget);
350 /* Make the window for the tree */
353 attributes.width = tree_view->priv->width;
354 attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
355 attributes.event_mask = GDK_EXPOSURE_MASK |
357 GDK_POINTER_MOTION_MASK |
358 GDK_ENTER_NOTIFY_MASK |
359 GDK_LEAVE_NOTIFY_MASK |
360 GDK_BUTTON_PRESS_MASK |
361 GDK_BUTTON_RELEASE_MASK |
362 gtk_widget_get_events (widget);
364 tree_view->priv->bin_window = gdk_window_new (widget->window,
365 &attributes, attributes_mask);
366 gdk_window_set_user_data (tree_view->priv->bin_window, widget);
368 /* Make the column header window */
371 attributes.width = MAX (tree_view->priv->width, widget->allocation.width);
372 attributes.height = tree_view->priv->header_height;
373 attributes.event_mask = (GDK_EXPOSURE_MASK |
375 GDK_BUTTON_PRESS_MASK |
376 GDK_BUTTON_RELEASE_MASK |
378 GDK_KEY_RELEASE_MASK) |
379 gtk_widget_get_events (widget);
381 tree_view->priv->header_window = gdk_window_new (widget->window,
382 &attributes, attributes_mask);
383 gdk_window_set_user_data (tree_view->priv->header_window, widget);
386 values.foreground = (widget->style->white.pixel==0 ?
387 widget->style->black:widget->style->white);
388 values.function = GDK_XOR;
389 values.subwindow_mode = GDK_INCLUDE_INFERIORS;
390 tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
395 /* Add them all up. */
396 widget->style = gtk_style_attach (widget->style, widget->window);
397 gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
398 gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
399 gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
401 tmp_list = tree_view->priv->children;
404 GtkTreeViewChild *child = tmp_list->data;
405 tmp_list = tmp_list->next;
407 gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
409 gtk_tree_view_realize_buttons (GTK_TREE_VIEW (widget));
410 _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, -1);
414 gtk_tree_view_unrealize (GtkWidget *widget)
416 GtkTreeView *tree_view;
418 g_return_if_fail (widget != NULL);
419 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
421 tree_view = GTK_TREE_VIEW (widget);
423 gdk_window_set_user_data (tree_view->priv->bin_window, NULL);
424 gdk_window_destroy (tree_view->priv->bin_window);
425 tree_view->priv->bin_window = NULL;
427 gdk_window_set_user_data (tree_view->priv->header_window, NULL);
428 gdk_window_destroy (tree_view->priv->header_window);
429 tree_view->priv->header_window = NULL;
431 gdk_gc_destroy (tree_view->priv->xor_gc);
432 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
433 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
437 gtk_tree_view_map (GtkWidget *widget)
440 GtkTreeView *tree_view;
442 GtkTreeViewColumn *column;
444 g_return_if_fail (widget != NULL);
445 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
447 tree_view = GTK_TREE_VIEW (widget);
449 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
451 tmp_list = tree_view->priv->children;
454 GtkTreeViewChild *child = tmp_list->data;
455 tmp_list = tmp_list->next;
457 if (GTK_WIDGET_VISIBLE (child->widget))
459 if (!GTK_WIDGET_MAPPED (child->widget))
460 gtk_widget_map (child->widget);
463 gdk_window_show (tree_view->priv->bin_window);
464 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
466 for (list = tree_view->priv->column; list; list = list->next)
469 gtk_widget_map (column->button);
471 for (list = tree_view->priv->column; list; list = list->next)
474 if (column->visible == FALSE)
476 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
478 gdk_window_raise (column->window);
479 gdk_window_show (column->window);
482 gdk_window_hide (column->window);
484 gdk_window_show (tree_view->priv->header_window);
486 gdk_window_show (widget->window);
490 gtk_tree_view_size_request (GtkWidget *widget,
491 GtkRequisition *requisition)
493 GtkTreeView *tree_view;
496 g_return_if_fail (widget != NULL);
497 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
499 tree_view = GTK_TREE_VIEW (widget);
501 requisition->width = 200;
502 requisition->height = 200;
504 tmp_list = tree_view->priv->children;
508 GtkTreeViewChild *child = tmp_list->data;
509 GtkRequisition child_requisition;
511 tmp_list = tmp_list->next;
513 gtk_widget_size_request (child->widget, &child_requisition);
518 gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
520 GtkTreeView *tree_view;
523 GtkTreeViewColumn *column;
524 GtkAllocation allocation;
527 tree_view = GTK_TREE_VIEW (widget);
530 allocation.height = tree_view->priv->header_height;
532 for (last_column = g_list_last (tree_view->priv->column);
533 last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
534 last_column = last_column->prev)
537 if (last_column == NULL)
540 for (list = tree_view->priv->column; list != last_column; list = list->next)
544 if (!column->visible)
547 allocation.x = width;
548 allocation.width = column->size;
549 width += column->size;
550 gtk_widget_size_allocate (column->button, &allocation);
553 gdk_window_move (column->window, width - TREE_VIEW_DRAG_WIDTH/2, 0);
556 allocation.x = width;
557 allocation.width = MAX (widget->allocation.width, tree_view->priv->width) - width;
558 gtk_widget_size_allocate (column->button, &allocation);
560 gdk_window_move (column->window,
561 allocation.x +allocation.width - TREE_VIEW_DRAG_WIDTH/2,
566 gtk_tree_view_size_allocate (GtkWidget *widget,
567 GtkAllocation *allocation)
570 GtkTreeView *tree_view;
572 g_return_if_fail (widget != NULL);
573 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
575 widget->allocation = *allocation;
577 tree_view = GTK_TREE_VIEW (widget);
579 tmp_list = tree_view->priv->children;
583 GtkAllocation allocation;
584 GtkRequisition requisition;
586 GtkTreeViewChild *child = tmp_list->data;
587 tmp_list = tmp_list->next;
589 allocation.x = child->x;
590 allocation.y = child->y;
591 gtk_widget_get_child_requisition (child->widget, &requisition);
592 allocation.width = requisition.width;
593 allocation.height = requisition.height;
595 gtk_widget_size_allocate (child->widget, &allocation);
598 if (GTK_WIDGET_REALIZED (widget))
600 gdk_window_move_resize (widget->window,
601 allocation->x, allocation->y,
602 allocation->width, allocation->height);
603 gdk_window_move_resize (tree_view->priv->header_window,
605 MAX (tree_view->priv->width, allocation->width),
606 tree_view->priv->header_height);
609 tree_view->priv->hadjustment->page_size = allocation->width;
610 tree_view->priv->hadjustment->page_increment = allocation->width / 2;
611 tree_view->priv->hadjustment->lower = 0;
612 tree_view->priv->hadjustment->upper = tree_view->priv->width;
613 if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
614 tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
615 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
617 tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
618 tree_view->priv->vadjustment->page_increment = (allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
619 tree_view->priv->vadjustment->lower = 0;
620 tree_view->priv->vadjustment->upper = tree_view->priv->height;
621 if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
622 gtk_adjustment_set_value (tree_view->priv->vadjustment,
623 (gfloat) MAX (tree_view->priv->height - allocation->height, 0));
624 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
626 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
627 gtk_tree_view_size_allocate_buttons (widget);
631 gtk_tree_view_draw (GtkWidget *widget,
635 GtkTreeView *tree_view;
636 GtkTreeViewColumn *column;
637 GdkRectangle child_area;
639 g_return_if_fail (widget != NULL);
640 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
642 tree_view = GTK_TREE_VIEW (widget);
644 /* We don't have any way of telling themes about this properly,
645 * so we just assume a background pixmap
647 if (!GTK_WIDGET_APP_PAINTABLE (widget))
649 gdk_window_clear_area (tree_view->priv->bin_window,
650 area->x, area->y, area->width, area->height);
651 gdk_window_clear_area (tree_view->priv->header_window,
652 area->x, area->y, area->width, area->height);
655 tmp_list = tree_view->priv->children;
658 GtkTreeViewChild *child = tmp_list->data;
659 tmp_list = tmp_list->next;
661 if (gtk_widget_intersect (child->widget, area, &child_area))
662 gtk_widget_draw (child->widget, &child_area);
664 for (tmp_list = tree_view->priv->column; tmp_list; tmp_list = tmp_list->next)
666 column = tmp_list->data;
667 if (!column->visible)
669 if (column->button &&
670 gtk_widget_intersect(column->button, area, &child_area))
671 gtk_widget_draw (column->button, &child_area);
675 /* Warning: Very scary function.
676 * Modify at your own risk
679 gtk_tree_view_bin_expose (GtkWidget *widget,
680 GdkEventExpose *event)
682 GtkTreeView *tree_view;
686 GtkRBNode *node, *last_node = NULL;
687 GtkRBNode *cursor = NULL;
688 GtkRBTree *cursor_tree = NULL, *last_tree = NULL;
689 GtkTreeNode tree_node;
690 GtkCellRenderer *cell;
692 gint y_offset, x_offset, cell_offset;
695 GdkRectangle background_area;
696 GdkRectangle cell_area;
698 gboolean last_selected;
700 g_return_val_if_fail (widget != NULL, FALSE);
701 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
703 tree_view = GTK_TREE_VIEW (widget);
705 if (tree_view->priv->tree == NULL)
708 gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
709 /* we want to account for a potential HEADER offset.
710 * That is, if the header exists, we want to offset our event by its
711 * height to find the right node.
713 new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
714 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
715 new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
717 &node) + new_y - event->area.y;
721 /* See if the last node was selected */
722 _gtk_rbtree_prev_full (tree, node, &last_tree, &last_node);
723 last_selected = (last_node && GTK_RBNODE_FLAG_SET (last_node, GTK_RBNODE_IS_SELECTED));
725 /* find the path for the node */
726 path = _gtk_tree_view_find_path ((GtkTreeView *)widget,
729 tree_node = gtk_tree_model_get_node (tree_view->priv->model, path);
730 depth = gtk_tree_path_get_depth (path);
731 gtk_tree_path_free (path);
733 if (tree_view->priv->cursor)
734 _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor, &cursor_tree, &cursor);
736 /* Actually process the expose event. To do this, we want to
737 * start at the first node of the event, and walk the tree in
738 * order, drawing each successive node.
743 /* Need to think about this more.
744 if (tree_view->priv->show_expanders)
745 max_height = MAX (TREE_VIEW_EXPANDER_MIN_HEIGHT, GTK_RBNODE_GET_HEIGHT (node));
748 max_height = GTK_RBNODE_GET_HEIGHT (node);
750 x_offset = -event->area.x;
753 background_area.y = y_offset + event->area.y + TREE_VIEW_VERTICAL_SEPERATOR;
754 background_area.height = max_height - TREE_VIEW_VERTICAL_SEPERATOR;
757 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
758 flags |= GTK_CELL_RENDERER_PRELIT;
760 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
762 flags |= GTK_CELL_RENDERER_SELECTED;
764 /* Draw the selection */
765 gdk_draw_rectangle (event->window,
766 GTK_WIDGET (tree_view)->style->bg_gc [GTK_STATE_SELECTED],
769 background_area.y - (last_selected?TREE_VIEW_VERTICAL_SEPERATOR:0),
771 background_area.height + (last_selected?TREE_VIEW_VERTICAL_SEPERATOR:0));
772 last_selected = TRUE;
776 last_selected = FALSE;
779 for (i = 0, list = tree_view->priv->column; i < tree_view->priv->columns; i++, list = list->next)
781 GtkTreeViewColumn *column = list->data;
783 if (!column->visible)
787 gtk_tree_view_column_set_cell_data (column,
788 tree_view->priv->model,
791 background_area.x = cell_offset;
792 background_area.width = TREE_VIEW_COLUMN_SIZE (column);
793 if (i == 0 && TREE_VIEW_DRAW_EXPANDERS(tree_view))
795 cell_area = background_area;
796 cell_area.x += depth*tree_view->priv->tab_offset;
797 cell_area.width -= depth*tree_view->priv->tab_offset;
798 gtk_cell_renderer_render (cell,
805 if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
808 gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, 0);
809 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
811 event->area.y + y_offset,
817 cell_area = background_area;
818 gtk_cell_renderer_render (cell,
826 cell_offset += TREE_VIEW_COLUMN_SIZE (column);
829 if (node == cursor &&
830 GTK_WIDGET_HAS_FOCUS (widget))
831 gtk_tree_view_draw_focus (widget);
833 y_offset += max_height;
836 tree = node->children;
838 while (node->left != tree->nil)
840 tree_node = gtk_tree_model_node_children (tree_view->priv->model, tree_node);
841 cell = gtk_tree_view_get_column (tree_view, 0)->cell;
845 TREE_VIEW_INTERNAL_ASSERT (tree_node != NULL, FALSE);
849 gboolean done = FALSE;
852 node = _gtk_rbtree_next (tree, node);
855 gtk_tree_model_node_next (tree_view->priv->model, &tree_node);
856 cell = gtk_tree_view_get_column (tree_view, 0)->cell;
860 TREE_VIEW_INTERNAL_ASSERT (tree_node != NULL, FALSE);
864 node = tree->parent_node;
865 tree = tree->parent_tree;
867 /* we've run out of tree. It's okay though, as we'd only break
868 * out of the while loop below. */
870 tree_node = gtk_tree_model_node_parent (tree_view->priv->model, tree_node);
874 TREE_VIEW_INTERNAL_ASSERT (tree_node != NULL, FALSE);
880 while (y_offset < event->area.height);
886 gtk_tree_view_expose (GtkWidget *widget,
887 GdkEventExpose *event)
889 GtkTreeView *tree_view;
891 g_return_val_if_fail (widget != NULL, FALSE);
892 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
894 tree_view = GTK_TREE_VIEW (widget);
896 if (event->window == tree_view->priv->bin_window)
897 return gtk_tree_view_bin_expose (widget, event);
903 gtk_tree_view_motion (GtkWidget *widget,
904 GdkEventMotion *event)
906 GtkTreeView *tree_view;
912 g_return_val_if_fail (widget != NULL, FALSE);
913 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
915 tree_view = GTK_TREE_VIEW (widget);
917 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
922 if (event->is_hint || event->window != widget->window)
923 gtk_widget_get_pointer (widget, &x, NULL);
927 new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos, &x);
928 if (x != tree_view->priv->x_drag)
930 gtk_tree_view_column_set_size (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), tree_view->priv->drag_pos), new_width);
933 /* FIXME: We need to scroll */
934 _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, tree_view->priv->height);
938 /* Sanity check it */
939 if (event->window != tree_view->priv->bin_window)
941 if (tree_view->priv->tree == NULL)
944 if (tree_view->priv->prelight_node != NULL)
946 if ((((gint) event->y - TREE_VIEW_HEADER_HEIGHT (tree_view) < tree_view->priv->prelight_offset) ||
947 ((gint) event->y - TREE_VIEW_HEADER_HEIGHT (tree_view) >=
948 (tree_view->priv->prelight_offset + GTK_RBNODE_GET_HEIGHT (tree_view->priv->prelight_node))) ||
949 ((gint) event->x > tree_view->priv->tab_offset)))
950 /* We need to unprelight the old one. */
952 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
954 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
955 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
956 tree_view->priv->prelight_node,
957 tree_view->priv->prelight_offset,
960 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
963 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
964 tree_view->priv->prelight_node = NULL;
965 tree_view->priv->prelight_tree = NULL;
966 tree_view->priv->prelight_offset = 0;
970 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
971 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
973 &node) + new_y - (gint)event->y;
978 /* If we are currently pressing down a button, we don't want to prelight anything else. */
979 if ((tree_view->priv->button_pressed_node != NULL) &&
980 (tree_view->priv->button_pressed_node != node))
983 /* Do we want to prelight a tab? */
984 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
985 if (event->x <= tree_view->priv->tab_offset &&
987 ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
989 tree_view->priv->prelight_offset = event->y+y_offset;
990 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
993 tree_view->priv->prelight_node = node;
994 tree_view->priv->prelight_tree = tree;
995 tree_view->priv->prelight_offset = event->y+y_offset;
997 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
998 gtk_widget_queue_draw (widget);
1003 /* Is this function necessary? Can I get an enter_notify event w/o either
1004 * an expose event or a mouse motion event?
1007 gtk_tree_view_enter_notify (GtkWidget *widget,
1008 GdkEventCrossing *event)
1010 GtkTreeView *tree_view;
1016 g_return_val_if_fail (widget != NULL, FALSE);
1017 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1019 tree_view = GTK_TREE_VIEW (widget);
1021 /* Sanity check it */
1022 if (event->window != tree_view->priv->bin_window)
1024 if (tree_view->priv->tree == NULL)
1027 if ((tree_view->priv->button_pressed_node != NULL) &&
1028 (tree_view->priv->button_pressed_node != node))
1031 /* find the node internally */
1032 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1033 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1034 new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
1036 &node) + new_y - (gint)event->y;
1041 /* Do we want to prelight a tab? */
1042 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1043 if (event->x <= tree_view->priv->tab_offset &&
1045 ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT))
1047 tree_view->priv->prelight_offset = event->y+y_offset;
1048 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1051 tree_view->priv->prelight_node = node;
1052 tree_view->priv->prelight_tree = tree;
1053 tree_view->priv->prelight_offset = event->y+y_offset;
1055 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
1056 gtk_widget_queue_draw (widget);
1062 gtk_tree_view_leave_notify (GtkWidget *widget,
1063 GdkEventCrossing *event)
1065 GtkTreeView *tree_view;
1067 g_return_val_if_fail (widget != NULL, FALSE);
1068 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1070 tree_view = GTK_TREE_VIEW (widget);
1072 if (tree_view->priv->prelight_node != NULL)
1074 GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
1075 tree_view->priv->prelight_node = NULL;
1076 tree_view->priv->prelight_tree = NULL;
1077 tree_view->priv->prelight_offset = 0;
1078 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
1079 gtk_widget_queue_draw (widget);
1085 gtk_tree_view_button_press (GtkWidget *widget,
1086 GdkEventButton *event)
1088 GtkTreeView *tree_view;
1090 GtkTreeViewColumn *column;
1092 GdkRectangle background_area;
1093 GdkRectangle cell_area;
1095 g_return_val_if_fail (widget != NULL, FALSE);
1096 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1097 g_return_val_if_fail (event != NULL, FALSE);
1099 tree_view = GTK_TREE_VIEW (widget);
1101 if (event->window == tree_view->priv->bin_window)
1111 if (!GTK_WIDGET_HAS_FOCUS (widget))
1112 gtk_widget_grab_focus (widget);
1113 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1114 /* are we in an arrow? */
1115 if (tree_view->priv->prelight_node != FALSE && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1117 if (event->button == 1)
1119 gtk_grab_add (widget);
1120 tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
1121 tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
1122 gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
1123 tree_view->priv->prelight_node,
1124 tree_view->priv->prelight_offset,
1131 /* find the node that was clicked */
1132 new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
1133 y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
1134 new_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
1136 &node) + new_y - (gint)event->y;
1139 /* We clicked in dead space */
1142 /* Get the path and the node */
1143 path = _gtk_tree_view_find_path (tree_view, tree, node);
1144 depth = gtk_tree_path_get_depth (path);
1145 background_area.y = y_offset + event->y + TREE_VIEW_VERTICAL_SEPERATOR;
1146 background_area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPERATOR;
1147 background_area.x = 0;
1148 /* Let the cell have a chance at selecting it. */
1150 for (i = 0, list = tree_view->priv->column; i < tree_view->priv->columns; i++, list = list->next)
1152 GtkTreeViewColumn *column = list->data;
1153 GtkCellRenderer *cell;
1154 GtkTreeNode tree_node;
1156 if (!column->visible)
1159 background_area.width = TREE_VIEW_COLUMN_SIZE (column);
1160 if (i == 0 && TREE_VIEW_DRAW_EXPANDERS(tree_view))
1162 cell_area = background_area;
1163 cell_area.x += depth*tree_view->priv->tab_offset;
1164 cell_area.width -= depth*tree_view->priv->tab_offset;
1168 cell_area = background_area;
1171 cell = column->cell;
1173 if ((background_area.x > (gint) event->x) ||
1174 (background_area.y > (gint) event->y) ||
1175 (background_area.x + background_area.width <= (gint) event->x) ||
1176 (background_area.y + background_area.height <= (gint) event->y))
1178 background_area.x += background_area.width;
1182 tree_node = gtk_tree_model_get_node (tree_view->priv->model,
1184 gtk_tree_view_column_set_cell_data (column,
1185 tree_view->priv->model,
1188 path_string = gtk_tree_path_to_string (path);
1189 if (gtk_cell_renderer_event (cell,
1198 g_free (path_string);
1199 gtk_tree_path_free (path);
1204 g_free (path_string);
1208 /* Handle the selection */
1209 if (tree_view->priv->selection == NULL)
1210 gtk_tree_selection_new_with_tree_view (tree_view);
1212 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
1217 gtk_tree_path_free (path);
1221 for (i = 0, list = tree_view->priv->column; list; list = list->next, i++)
1223 column = list->data;
1224 if (event->window == column->window &&
1225 column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE &&
1230 if (gdk_pointer_grab (column->window, FALSE,
1231 GDK_POINTER_MOTION_HINT_MASK |
1232 GDK_BUTTON1_MOTION_MASK |
1233 GDK_BUTTON_RELEASE_MASK,
1234 NULL, NULL, event->time))
1237 gtk_grab_add (widget);
1238 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1240 /* block attached dnd signal handler */
1241 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1243 gtk_signal_handler_block_by_data (GTK_OBJECT (widget), drag_data);
1245 if (!GTK_WIDGET_HAS_FOCUS (widget))
1246 gtk_widget_grab_focus (widget);
1248 tree_view->priv->drag_pos = i;
1249 tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
1256 gtk_tree_view_button_release (GtkWidget *widget,
1257 GdkEventButton *event)
1259 GtkTreeView *tree_view;
1261 g_return_val_if_fail (widget != NULL, FALSE);
1262 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1263 g_return_val_if_fail (event != NULL, FALSE);
1265 tree_view = GTK_TREE_VIEW (widget);
1267 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
1274 i = tree_view->priv->drag_pos;
1275 tree_view->priv->drag_pos = -1;
1277 /* unblock attached dnd signal handler */
1278 drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
1280 gtk_signal_handler_unblock_by_data (GTK_OBJECT (widget), drag_data);
1282 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
1283 gtk_widget_get_pointer (widget, &x, NULL);
1284 gtk_grab_remove (widget);
1285 gdk_pointer_ungrab (event->time);
1287 width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
1288 gtk_tree_view_column_set_size (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
1292 if (tree_view->priv->button_pressed_node == NULL)
1295 if (event->button == 1)
1297 gtk_grab_remove (widget);
1298 if (tree_view->priv->button_pressed_node == tree_view->priv->prelight_node && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
1301 GtkTreeNode tree_node;
1303 /* Actually activate the node */
1304 if (tree_view->priv->button_pressed_node->children == NULL)
1306 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
1307 tree_view->priv->button_pressed_tree,
1308 tree_view->priv->button_pressed_node);
1309 tree_view->priv->button_pressed_node->children = _gtk_rbtree_new ();
1310 tree_view->priv->button_pressed_node->children->parent_tree = tree_view->priv->button_pressed_tree;
1311 tree_view->priv->button_pressed_node->children->parent_node = tree_view->priv->button_pressed_node;
1312 tree_node = gtk_tree_model_get_node (tree_view->priv->model, path);
1313 tree_node = gtk_tree_model_node_children (tree_view->priv->model, tree_node);
1315 gtk_tree_view_build_tree (tree_view,
1316 tree_view->priv->button_pressed_node->children,
1318 gtk_tree_path_get_depth (path) + 1,
1320 GTK_WIDGET_REALIZED (widget));
1324 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (widget),
1325 tree_view->priv->button_pressed_node->children,
1326 tree_view->priv->button_pressed_node->children->root);
1327 tree_node = gtk_tree_model_get_node (tree_view->priv->model, path);
1329 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (widget),
1330 tree_view->priv->button_pressed_node->children,
1332 gtk_tree_path_get_depth (path));
1333 _gtk_rbtree_remove (tree_view->priv->button_pressed_node->children);
1335 gtk_tree_path_free (path);
1337 _gtk_tree_view_set_size (GTK_TREE_VIEW (widget), -1, -1);
1338 gtk_widget_queue_resize (widget);
1341 tree_view->priv->button_pressed_node = NULL;
1349 gtk_tree_view_draw_focus (GtkWidget *widget)
1351 GtkTreeView *tree_view;
1352 GtkRBTree *cursor_tree = NULL;
1353 GtkRBNode *cursor = NULL;
1355 g_return_if_fail (widget != NULL);
1356 g_return_if_fail (GTK_IS_TREE_VIEW (widget));
1358 tree_view = GTK_TREE_VIEW (widget);
1360 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
1362 if (tree_view->priv->cursor == NULL)
1365 _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor, &cursor_tree, &cursor);
1369 gdk_draw_rectangle (tree_view->priv->bin_window,
1370 widget->style->fg_gc[GTK_STATE_NORMAL],
1373 _gtk_rbtree_node_find_offset (cursor_tree, cursor) + TREE_VIEW_HEADER_HEIGHT (tree_view),
1374 (gint) MAX (tree_view->priv->width, tree_view->priv->hadjustment->upper),
1375 GTK_RBNODE_GET_HEIGHT (cursor));
1380 gtk_tree_view_focus_in (GtkWidget *widget,
1381 GdkEventFocus *event)
1383 GtkTreeView *tree_view;
1385 g_return_val_if_fail (widget != NULL, FALSE);
1386 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1387 g_return_val_if_fail (event != NULL, FALSE);
1389 tree_view = GTK_TREE_VIEW (widget);
1391 GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
1393 gtk_widget_draw_focus (widget);
1400 gtk_tree_view_focus_out (GtkWidget *widget,
1401 GdkEventFocus *event)
1403 g_return_val_if_fail (widget != NULL, FALSE);
1404 g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
1405 g_return_val_if_fail (event != NULL, FALSE);
1407 GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
1409 gtk_widget_queue_draw (widget);
1414 /* FIXME: It would be neat to someday make the headers a seperate widget that
1415 * can be shared between various apps
1417 /* Returns TRUE if the focus is within the headers, after the focus operation is
1421 gtk_tree_view_header_focus (GtkTreeView *tree_view,
1422 GtkDirectionType dir)
1424 GtkWidget *focus_child;
1425 GtkContainer *container;
1427 GList *last_column, *first_column;
1430 if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
1433 focus_child = GTK_CONTAINER (tree_view)->focus_child;
1434 container = GTK_CONTAINER (tree_view);
1436 for (last_column = g_list_last (tree_view->priv->column);
1438 !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
1439 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
1440 last_column = last_column->prev)
1443 for (first_column = tree_view->priv->column;
1445 !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible) &&
1446 GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button);
1447 first_column = first_column->next)
1450 /* no headers are visible, or are focussable. We can't focus in or out.
1451 * I wonder if focussable is a real word...
1453 if (last_column == NULL)
1455 gtk_container_set_focus_child (container, NULL);
1459 /* First thing we want to handle is entering and leaving the headers.
1463 case GTK_DIR_TAB_BACKWARD:
1466 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
1467 gtk_container_set_focus_child (container, focus_child);
1468 gtk_widget_grab_focus (focus_child);
1471 if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
1478 case GTK_DIR_TAB_FORWARD:
1481 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1482 gtk_container_set_focus_child (container, focus_child);
1483 gtk_widget_grab_focus (focus_child);
1486 if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
1496 focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
1497 gtk_container_set_focus_child (container, focus_child);
1498 gtk_widget_grab_focus (focus_child);
1501 if (focus_child == GTK_TREE_VIEW_COLUMN (first_column->data)->button)
1511 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1512 gtk_container_set_focus_child (container, focus_child);
1513 gtk_widget_grab_focus (focus_child);
1516 if (focus_child == GTK_TREE_VIEW_COLUMN (last_column->data)->button)
1526 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1527 gtk_container_set_focus_child (container, focus_child);
1528 gtk_widget_grab_focus (focus_child);
1539 focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
1540 gtk_container_set_focus_child (container, focus_child);
1541 gtk_widget_grab_focus (focus_child);
1550 /* We need to move the focus to the next button. */
1553 for (tmp_list = tree_view->priv->column; tmp_list; tmp_list = tmp_list->next)
1554 if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
1556 if (gtk_container_focus (GTK_CONTAINER (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button), dir))
1558 /* The focus moves inside the button. */
1559 /* This is probably a great example of bad UI */
1565 /* We need to move the focus among the row of buttons. */
1568 GtkTreeViewColumn *column;
1570 if (dir == GTK_DIR_RIGHT || dir == GTK_DIR_TAB_FORWARD)
1571 tmp_list = tmp_list->next;
1573 tmp_list = tmp_list->prev;
1575 if (tmp_list == NULL)
1577 g_warning ("Internal button not found");
1580 column = tmp_list->data;
1581 if (column->button &&
1583 GTK_WIDGET_CAN_FOCUS (column->button))
1585 focus_child = column->button;
1586 gtk_container_set_focus_child (container, column->button);
1587 gtk_widget_grab_focus (column->button);
1594 /* if focus child is non-null, we assume it's been set to the current focus child
1598 /* If the following isn't true, then the view is smaller then the scrollpane.
1600 if ((focus_child->allocation.x + focus_child->allocation.width) <=
1601 (tree_view->priv->hadjustment->upper))
1603 /* Scroll to the button, if needed */
1604 if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
1605 (focus_child->allocation.x + focus_child->allocation.width))
1606 gtk_adjustment_set_value (tree_view->priv->hadjustment,
1607 focus_child->allocation.x + focus_child->allocation.width -
1608 tree_view->priv->hadjustment->page_size);
1609 else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
1610 gtk_adjustment_set_value (tree_view->priv->hadjustment,
1611 focus_child->allocation.x);
1616 gtk_container_set_focus_child (container, NULL);
1619 return (focus_child != NULL);
1622 /* WARNING: Scary function */
1624 gtk_tree_view_focus (GtkContainer *container,
1625 GtkDirectionType direction)
1627 GtkTreeView *tree_view;
1628 GtkWidget *focus_child;
1630 GtkRBTree *cursor_tree;
1631 GtkRBNode *cursor_node;
1633 g_return_val_if_fail (container != NULL, FALSE);
1634 g_return_val_if_fail (GTK_IS_TREE_VIEW (container), FALSE);
1635 g_return_val_if_fail (GTK_WIDGET_VISIBLE (container), FALSE);
1637 tree_view = GTK_TREE_VIEW (container);
1639 if (!GTK_WIDGET_IS_SENSITIVE (container))
1641 if (tree_view->priv->tree == NULL)
1644 focus_child = container->focus_child;
1646 /* Case 1. Headers have focus. */
1652 case GTK_DIR_TAB_BACKWARD:
1653 return (gtk_tree_view_header_focus (tree_view, direction));
1655 gtk_container_set_focus_child (container, NULL);
1657 case GTK_DIR_TAB_FORWARD:
1660 if (direction == GTK_DIR_DOWN)
1662 gtk_container_set_focus_child (container, NULL);
1666 if (gtk_tree_view_header_focus (tree_view, direction))
1669 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1670 gtk_widget_grab_focus (GTK_WIDGET (container));
1672 if (tree_view->priv->selection == NULL)
1673 gtk_tree_selection_new_with_tree_view (tree_view);
1675 /* if there is no keyboard focus yet, we select the first node
1677 if (tree_view->priv->cursor == NULL)
1678 tree_view->priv->cursor = gtk_tree_path_new_root ();
1679 if (tree_view->priv->cursor)
1680 gtk_tree_selection_select_path (tree_view->priv->selection,
1681 tree_view->priv->cursor);
1682 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1687 /* Case 2. We don't have focus at all. */
1688 if (!GTK_WIDGET_HAS_FOCUS (container))
1690 if ((direction == GTK_DIR_TAB_FORWARD) ||
1691 (direction == GTK_DIR_RIGHT) ||
1692 (direction == GTK_DIR_DOWN))
1694 if (gtk_tree_view_header_focus (tree_view, direction))
1698 /* The headers didn't want the focus, so we take it. */
1699 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
1700 gtk_widget_grab_focus (GTK_WIDGET (container));
1702 if (tree_view->priv->selection == NULL)
1703 gtk_tree_selection_new_with_tree_view (tree_view);
1705 if (tree_view->priv->cursor == NULL)
1706 tree_view->priv->cursor = gtk_tree_path_new_root ();
1708 if (tree_view->priv->cursor)
1709 gtk_tree_selection_select_path (tree_view->priv->selection,
1710 tree_view->priv->cursor);
1711 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1715 /* Case 3. We have focus already, but no cursor. We pick the first one
1716 * and run with it. */
1717 if (tree_view->priv->cursor == NULL)
1719 /* We lost our cursor somehow. Arbitrarily select the first node, and
1722 tree_view->priv->cursor = gtk_tree_path_new_root ();
1724 if (tree_view->priv->cursor)
1725 gtk_tree_selection_select_path (tree_view->priv->selection,
1726 tree_view->priv->cursor);
1727 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
1729 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1734 /* Case 3. We have focus already. Move the cursor. */
1735 if (direction == GTK_DIR_LEFT)
1738 val = tree_view->priv->hadjustment->value - tree_view->priv->hadjustment->page_size/2;
1739 val = MAX (val, 0.0);
1740 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
1741 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
1744 if (direction == GTK_DIR_RIGHT)
1747 val = tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size/2;
1748 val = MIN (tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size, val);
1749 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->hadjustment), val);
1750 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
1756 _gtk_tree_view_find_node (tree_view, tree_view->priv->cursor,
1761 case GTK_DIR_TAB_BACKWARD:
1763 _gtk_rbtree_prev_full (cursor_tree,
1768 case GTK_DIR_TAB_FORWARD:
1770 _gtk_rbtree_next_full (cursor_tree,
1781 GdkModifierType state = 0;
1783 event = gdk_event_peek ();
1784 if (event && event->type == GDK_KEY_PRESS)
1785 /* FIXME: This doesn't seem to work. )-:
1786 * I fear the event may already have been gotten */
1787 state = ((GdkEventKey *)event)->state;
1790 gdk_event_free (event);
1791 gtk_tree_path_free (tree_view->priv->cursor);
1793 tree_view->priv->cursor = _gtk_tree_view_find_path (tree_view,
1796 if (tree_view->priv->cursor)
1797 _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
1800 tree_view->priv->cursor,
1802 gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
1803 gtk_widget_grab_focus (GTK_WIDGET (tree_view));
1804 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
1808 /* At this point, we've progressed beyond the edge of the rows. */
1810 if ((direction == GTK_DIR_LEFT) ||
1811 (direction == GTK_DIR_TAB_BACKWARD) ||
1812 (direction == GTK_DIR_UP))
1813 /* We can't go back anymore. Try the headers */
1814 return (gtk_tree_view_header_focus (tree_view, direction));
1816 /* we've reached the end of the tree. Go on. */
1823 gtk_tree_view_remove (GtkContainer *container,
1826 GtkTreeView *tree_view;
1827 GtkTreeViewChild *child = NULL;
1830 g_return_if_fail (container != NULL);
1831 g_return_if_fail (GTK_IS_TREE_VIEW (container));
1833 tree_view = GTK_TREE_VIEW (container);
1835 tmp_list = tree_view->priv->children;
1838 child = tmp_list->data;
1839 if (child->widget == widget)
1841 tmp_list = tmp_list->next;
1846 gtk_widget_unparent (widget);
1848 tree_view->priv->children = g_list_remove_link (tree_view->priv->children, tmp_list);
1849 g_list_free_1 (tmp_list);
1855 gtk_tree_view_forall (GtkContainer *container,
1856 gboolean include_internals,
1857 GtkCallback callback,
1858 gpointer callback_data)
1860 GtkTreeView *tree_view;
1861 GtkTreeViewChild *child = NULL;
1862 GtkTreeViewColumn *column;
1865 g_return_if_fail (container != NULL);
1866 g_return_if_fail (GTK_IS_TREE_VIEW (container));
1867 g_return_if_fail (callback != NULL);
1869 tree_view = GTK_TREE_VIEW (container);
1871 tmp_list = tree_view->priv->children;
1874 child = tmp_list->data;
1875 tmp_list = tmp_list->next;
1877 (* callback) (child->widget, callback_data);
1879 if (include_internals == FALSE)
1882 for (tmp_list = tree_view->priv->column; tmp_list; tmp_list = tmp_list->next)
1884 column = tmp_list->data;
1886 (* callback) (column->button, callback_data);
1890 /* TreeModel Methods
1894 gtk_tree_view_node_changed (GtkTreeModel *model,
1896 GtkTreeNode tree_node,
1899 GtkTreeView *tree_view = (GtkTreeView *)data;
1903 gboolean dirty_marked;
1905 g_return_if_fail (path != NULL || node != NULL);
1908 path = gtk_tree_model_get_path (model, tree_node);
1909 else if (tree_node == NULL)
1910 tree_node = gtk_tree_model_get_node (model, path);
1912 if (_gtk_tree_view_find_node (tree_view,
1916 /* We aren't actually showing the node */
1919 dirty_marked = gtk_tree_view_discover_dirty_node (tree_view,
1921 gtk_tree_path_get_depth (path),
1924 if (GTK_RBNODE_GET_HEIGHT (node) != height + TREE_VIEW_VERTICAL_SEPERATOR)
1926 _gtk_rbtree_node_set_height (tree, node, height + TREE_VIEW_VERTICAL_SEPERATOR);
1927 gtk_widget_queue_resize (GTK_WIDGET (data));
1931 gtk_widget_queue_resize (GTK_WIDGET (data));
1934 /* FIXME: just redraw the node */
1935 gtk_widget_queue_resize (GTK_WIDGET (data));
1940 gtk_tree_view_node_inserted (GtkTreeModel *model,
1942 GtkTreeNode tree_node,
1945 GtkTreeView *tree_view = (GtkTreeView *) data;
1947 GtkRBTree *tmptree, *tree;
1948 GtkRBNode *tmpnode = NULL;
1953 tmptree = tree = tree_view->priv->tree;
1954 g_return_if_fail (path != NULL || tree_node != NULL);
1957 path = gtk_tree_model_get_path (model, tree_node);
1958 else if (tree_node == NULL)
1959 tree_node = gtk_tree_model_get_node (model, path);
1961 depth = gtk_tree_path_get_depth (path);
1962 indices = gtk_tree_path_get_indices (path);
1964 /* First, find the parent tree */
1965 while (i < depth - 1)
1967 if (tmptree == NULL)
1969 /* We aren't showing the node */
1973 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
1974 if (tmpnode == NULL)
1976 g_warning ("A node was inserted with a parent that's not in the tree.\n" \
1977 "This possibly means that a GtkTreeModel inserted a child node\n" \
1978 "before the parent was inserted.");
1981 else if (!GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_IS_PARENT))
1983 /* In theory, the model should have emitted child_toggled here. We
1984 * try to catch it anyway, just to be safe, in case the model hasn't.
1986 GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
1989 gtk_tree_view_node_child_toggled (model, tmppath, NULL, data);
1990 gtk_tree_path_free (tmppath);
1994 tmptree = tmpnode->children;
2002 /* next, update the selection */
2003 if (tree_view->priv->anchor)
2005 gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
2006 gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
2008 for (i = 0; i < depth && i < select_depth; i++)
2010 if (indices[i] < select_indices[i])
2012 select_indices[i]++;
2015 else if (indices[i] > select_indices[i])
2017 else if (i == depth - 1)
2019 select_indices[i]++;
2025 max_height = gtk_tree_view_insert_node_height (tree_view,
2029 if (indices[depth - 1] == 0)
2031 tmpnode = _gtk_rbtree_find_count (tree, 1);
2032 _gtk_rbtree_insert_before (tree, tmpnode, max_height);
2036 tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
2037 _gtk_rbtree_insert_after (tree, tmpnode, max_height);
2040 _gtk_tree_view_set_size (tree_view, -1, tree_view->priv->height + max_height);
2044 gtk_tree_view_node_child_toggled (GtkTreeModel *model,
2046 GtkTreeNode tree_node,
2049 GtkTreeView *tree_view = (GtkTreeView *)data;
2054 g_return_if_fail (path != NULL || node != NULL);
2057 path = gtk_tree_model_get_path (model, tree_node);
2058 else if (tree_node == NULL)
2059 tree_node = gtk_tree_model_get_node (model, path);
2061 if (_gtk_tree_view_find_node (tree_view,
2065 /* We aren't actually showing the node */
2068 has_child = gtk_tree_model_node_has_child (model, tree_node);
2071 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT) == has_child)
2075 GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PARENT);
2077 GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_IS_PARENT);
2079 if (has_child && GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
2081 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2082 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS))
2085 for (list = tree_view->priv->column; list; list = list->next)
2086 if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
2088 GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
2092 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
2096 /* FIXME: Just redraw the node */
2097 gtk_widget_queue_draw (GTK_WIDGET (tree_view));
2102 gtk_tree_view_node_deleted (GtkTreeModel *model,
2106 GtkTreeView *tree_view = (GtkTreeView *)data;
2111 g_return_if_fail (path != NULL);
2113 if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
2116 /* next, update the selection */
2117 if (tree_view->priv->anchor)
2120 gint depth = gtk_tree_path_get_depth (path);
2121 gint *indices = gtk_tree_path_get_indices (path);
2122 gint select_depth = gtk_tree_path_get_depth (tree_view->priv->anchor);
2123 gint *select_indices = gtk_tree_path_get_indices (tree_view->priv->anchor);
2125 if (gtk_tree_path_compare (path, tree_view->priv->anchor) == 0)
2127 if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED) &&
2128 tree_view->priv->selection)
2129 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->selection),
2130 "selection_changed");
2134 for (i = 0; i < depth && i < select_depth; i++)
2136 if (indices[i] < select_indices[i])
2138 select_indices[i] = MAX (select_indices[i], 0);
2141 else if (indices[i] > select_indices[i])
2143 else if (i == depth - 1)
2145 select_indices[i] = MAX (select_indices[i], 0);
2152 for (list = tree_view->priv->column; list; list = list->next)
2153 if (((GtkTreeViewColumn *)list->data)->visible &&
2154 ((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2155 ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
2157 if (tree->root->count == 1)
2158 _gtk_rbtree_remove (tree);
2160 _gtk_rbtree_remove_node (tree, node);
2162 _gtk_tree_view_set_size (GTK_TREE_VIEW (data), -1, -1);
2163 gtk_widget_queue_resize (data);
2166 /* Internal tree functions */
2168 gtk_tree_view_insert_node_height (GtkTreeView *tree_view,
2173 GtkTreeViewColumn *column;
2174 GtkCellRenderer *cell;
2175 gboolean first = TRUE;
2177 gint max_height = 0;
2179 /* do stuff with node */
2180 for (list = tree_view->priv->column; list; list = list->next)
2182 gint height = 0, width = 0;
2183 column = list->data;
2185 if (!column->visible)
2187 if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2193 cell = column->cell;
2194 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, node);
2196 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &height);
2197 max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPERATOR + height);
2199 if (first == TRUE && TREE_VIEW_DRAW_EXPANDERS (tree_view))
2200 column->size = MAX (column->size, depth * tree_view->priv->tab_offset + width);
2202 column->size = MAX (column->size, width);
2211 gtk_tree_view_build_tree (GtkTreeView *tree_view,
2216 gboolean calc_bounds)
2218 GtkRBNode *temp = NULL;
2228 max_height = gtk_tree_view_insert_node_height (tree_view,
2232 temp = _gtk_rbtree_insert_after (tree, temp, max_height);
2235 child = gtk_tree_model_node_children (tree_view->priv->model, node);
2238 temp->children = _gtk_rbtree_new ();
2239 temp->children->parent_tree = tree;
2240 temp->children->parent_node = temp;
2241 gtk_tree_view_build_tree (tree_view, temp->children, child, depth + 1, recurse, calc_bounds);
2244 if (gtk_tree_model_node_has_child (tree_view->priv->model, node))
2246 if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
2247 temp->flags ^= GTK_RBNODE_IS_PARENT;
2248 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
2251 while (gtk_tree_model_node_next (tree_view->priv->model, &node));
2255 gtk_tree_view_calc_size (GtkTreeView *tree_view,
2260 GtkRBNode *temp = tree->root;
2262 GtkCellRenderer *cell;
2264 GtkTreeViewColumn *column;
2268 /* FIXME: Make this function robust against internal inconsistencies! */
2271 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
2273 while (temp->left != tree->nil)
2279 /* Do stuff with node */
2280 for (list = tree_view->priv->column, i = 0; i < tree_view->priv->columns; list = list->next, i++)
2282 gint height = 0, width = 0;
2283 column = list->data;
2285 if (!column->visible)
2288 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, node);
2289 cell = column->cell;
2290 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &height);
2291 max_height = MAX (max_height, TREE_VIEW_VERTICAL_SEPERATOR + height);
2293 /* FIXME: I'm getting the width of all nodes here. )-: */
2294 if (column->dirty == FALSE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2297 if (i == 0 && TREE_VIEW_DRAW_EXPANDERS (tree_view))
2298 column->size = MAX (column->size, depth * tree_view->priv->tab_offset + width);
2300 column->size = MAX (column->size, width);
2302 _gtk_rbtree_node_set_height (tree, temp, max_height);
2303 child = gtk_tree_model_node_children (tree_view->priv->model, node);
2304 if (child != NULL && temp->children != NULL)
2305 gtk_tree_view_calc_size (tree_view, temp->children, child, depth + 1);
2306 temp = _gtk_rbtree_next (tree, temp);
2308 while (gtk_tree_model_node_next (tree_view->priv->model, &node));
2312 gtk_tree_view_discover_dirty_node (GtkTreeView *tree_view,
2317 GtkCellRenderer *cell;
2318 GtkTreeViewColumn *column;
2321 gint retval = FALSE;
2324 /* Do stuff with node */
2328 for (i = 0, list = tree_view->priv->column; list; list = list->next, i++)
2331 column = list->data;
2332 if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
2334 if (!column->visible)
2337 cell = column->cell;
2338 gtk_tree_view_column_set_cell_data (column, tree_view->priv->model, node);
2342 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, &tmpheight);
2343 *height = MAX (*height, tmpheight);
2347 gtk_cell_renderer_get_size (cell, GTK_WIDGET (tree_view), &width, NULL);
2349 if (i == 0 && TREE_VIEW_DRAW_EXPANDERS (tree_view))
2351 if (depth * tree_view->priv->tab_offset + width > column->size)
2353 column->dirty = TRUE;
2359 if (width > column->size)
2361 column->dirty = TRUE;
2371 gtk_tree_view_discover_dirty (GtkTreeView *tree_view,
2376 GtkRBNode *temp = tree->root;
2377 GtkTreeViewColumn *column;
2380 gboolean is_all_dirty;
2382 /* FIXME: Make this function robust against internal inconsistencies! */
2385 TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
2387 while (temp->left != tree->nil)
2392 is_all_dirty = TRUE;
2393 for (list = tree_view->priv->column; list; list = list->next)
2395 column = list->data;
2396 if (column->dirty == FALSE)
2398 is_all_dirty = FALSE;
2405 gtk_tree_view_discover_dirty_node (tree_view,
2409 child = gtk_tree_model_node_children (tree_view->priv->model, node);
2410 if (child != NULL && temp->children != NULL)
2411 gtk_tree_view_discover_dirty (tree_view, temp->children, child, depth + 1);
2412 temp = _gtk_rbtree_next (tree, temp);
2414 while (gtk_tree_model_node_next (tree_view->priv->model, &node));
2419 gtk_tree_view_check_dirty (GtkTreeView *tree_view)
2422 GtkTreeNode tree_node;
2423 gboolean dirty = FALSE;
2425 GtkTreeViewColumn *column;
2427 for (list = tree_view->priv->column; list; list = list->next)
2429 column = list->data;
2433 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
2435 column->size = column->button->requisition.width;
2442 path = gtk_tree_path_new_root ();
2445 tree_node = gtk_tree_model_get_node (tree_view->priv->model, path);
2446 gtk_tree_path_free (path);
2447 gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, tree_node, 1);
2448 _gtk_tree_view_set_size (tree_view, -1, -1);
2451 for (list = tree_view->priv->column; list; list = list->next)
2453 column = list->data;
2454 column->dirty = FALSE;
2459 gtk_tree_view_create_button (GtkTreeView *tree_view,
2463 GtkTreeViewColumn *column;
2465 column = g_list_nth (tree_view->priv->column, i)->data;
2466 gtk_widget_push_composite_child ();
2467 button = column->button = gtk_button_new ();
2468 gtk_widget_pop_composite_child ();
2470 gtk_widget_set_parent (button, GTK_WIDGET (tree_view));
2472 gtk_signal_connect (GTK_OBJECT (button), "clicked",
2473 (GtkSignalFunc) gtk_tree_view_button_clicked,
2474 (gpointer) tree_view);
2478 gtk_tree_view_create_buttons (GtkTreeView *tree_view)
2480 GtkWidget *alignment;
2482 GtkRequisition requisition;
2484 GtkTreeViewColumn *column;
2487 for (list = tree_view->priv->column, i = 0; list; list = list->next, i++)
2489 column = list->data;
2491 gtk_tree_view_create_button (tree_view, i);
2492 switch (column->justification)
2494 case GTK_JUSTIFY_LEFT:
2495 alignment = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
2497 case GTK_JUSTIFY_RIGHT:
2498 alignment = gtk_alignment_new (1.0, 0.5, 0.0, 0.0);
2500 case GTK_JUSTIFY_CENTER:
2501 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
2503 case GTK_JUSTIFY_FILL:
2505 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
2508 label = gtk_label_new (column->title);
2510 gtk_container_add (GTK_CONTAINER (alignment), label);
2511 gtk_container_add (GTK_CONTAINER (column->button), alignment);
2513 gtk_widget_show (label);
2514 gtk_widget_show (alignment);
2515 gtk_widget_size_request (column->button, &requisition);
2517 column->size = MAX (column->size, requisition.width);
2518 tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
2520 if (GTK_WIDGET_REALIZED (tree_view))
2522 gtk_tree_view_realize_buttons (tree_view);
2523 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
2525 /* We need to do this twice, as we need to map
2526 * all the buttons before we map the columns */
2527 for (list = tree_view->priv->column; list; list = list->next)
2529 column = list->data;
2530 if (column->visible == FALSE)
2532 gtk_widget_map (column->button);
2534 for (list = tree_view->priv->column; list; list = list->next)
2536 column = list->data;
2537 if (column->visible == FALSE)
2539 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
2541 gdk_window_raise (column->window);
2542 gdk_window_show (column->window);
2545 gdk_window_hide (column->window);
2552 gtk_tree_view_button_clicked (GtkWidget *widget,
2556 GtkTreeView *tree_view;
2558 g_return_if_fail (widget != NULL);
2559 g_return_if_fail (GTK_IS_TREE_VIEW (data));
2561 tree_view = GTK_TREE_VIEW (data);
2563 /* find the column who's button was pressed */
2564 for (list = tree_view->priv->column; list; list = list->next)
2565 if (GTK_TREE_VIEW_COLUMN (list->data)->button == widget)
2568 // gtk_signal_emit (GTK_OBJECT (clist), clist_signals[CLICK_COLUMN], i);
2571 /* Make sure the node is visible vertically */
2573 gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
2579 offset = _gtk_rbtree_node_find_offset (tree, node);
2581 /* we reverse the order, b/c in the unusual case of the
2582 * node's height being taller then the visible area, we'd rather
2583 * have the node flush to the top
2585 if (offset + GTK_RBNODE_GET_HEIGHT (node) >
2586 tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size)
2587 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2588 offset + GTK_RBNODE_GET_HEIGHT (node) -
2589 tree_view->priv->vadjustment->page_size);
2590 if (offset < tree_view->priv->vadjustment->value)
2591 gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
2595 /* This function could be more efficient.
2596 * I'll optimize it if profiling seems to imply that
2599 _gtk_tree_view_find_path (GtkTreeView *tree_view,
2604 GtkRBTree *tmp_tree;
2605 GtkRBNode *tmp_node, *last;
2608 path = gtk_tree_path_new ();
2610 g_return_val_if_fail (node != NULL, path);
2611 g_return_val_if_fail (node != tree->nil, path);
2613 count = 1 + node->left->count;
2616 tmp_node = node->parent;
2620 while (tmp_node != tmp_tree->nil)
2622 if (tmp_node->right == last)
2623 count += 1 + tmp_node->left->count;
2625 tmp_node = tmp_node->parent;
2627 gtk_tree_path_prepend_index (path, count - 1);
2628 last = tmp_tree->parent_node;
2629 tmp_tree = tmp_tree->parent_tree;
2632 count = 1 + last->left->count;
2633 tmp_node = last->parent;
2639 /* Returns wether or not it's a parent, or not */
2641 _gtk_tree_view_find_node (GtkTreeView *tree_view,
2646 GtkRBNode *tmpnode = NULL;
2647 GtkRBTree *tmptree = tree_view->priv->tree;
2648 gint *indices = gtk_tree_path_get_indices (path);
2649 gint depth = gtk_tree_path_get_depth (path);
2657 if (tmptree == NULL)
2663 tmpnode = _gtk_rbtree_find_count (tmptree, indices[i] + 1);
2670 tmptree = tmpnode->children;
2675 /* x and y are the mouse position
2678 gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
2686 GtkShadowType shadow;
2690 area.y = offset + TREE_VIEW_VERTICAL_SEPERATOR;
2691 area.width = tree_view->priv->tab_offset - 2;
2692 area.height = GTK_RBNODE_GET_HEIGHT (node) - TREE_VIEW_VERTICAL_SEPERATOR;
2694 if (node == tree_view->priv->button_pressed_node)
2696 if (x >= area.x && x <= (area.x + area.width) &&
2697 y >= area.y && y <= (area.y + area.height))
2699 state = GTK_STATE_ACTIVE;
2700 shadow = GTK_SHADOW_IN;
2704 state = GTK_STATE_NORMAL;
2705 shadow = GTK_SHADOW_OUT;
2710 state = (node==tree_view->priv->prelight_node&>K_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)?GTK_STATE_PRELIGHT:GTK_STATE_NORMAL);
2711 shadow = GTK_SHADOW_OUT;
2715 (((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT) &&
2718 points[0].x = area.x + 2;
2719 points[0].y = area.y + (area.height - TREE_VIEW_EXPANDER_HEIGHT)/2;
2720 points[1].x = points[0].x + TREE_VIEW_EXPANDER_WIDTH/2;
2721 points[1].y = points[0].y + TREE_VIEW_EXPANDER_HEIGHT/2;
2722 points[2].x = points[0].x;
2723 points[2].y = points[0].y + TREE_VIEW_EXPANDER_HEIGHT;
2727 gdk_draw_polygon (tree_view->priv->bin_window,
2728 GTK_WIDGET (tree_view)->style->base_gc[state],
2730 gdk_draw_polygon (tree_view->priv->bin_window,
2731 GTK_WIDGET (tree_view)->style->fg_gc[state],
2735 /* gtk_paint_arrow (GTK_WIDGET (tree_view)->style, */
2736 /* tree_view->priv->bin_window, */
2740 /* GTK_WIDGET (tree_view), */
2741 /* "GtkTreeView", */
2744 /* area.x, area.y, */
2745 /* area.width, area.height); */
2749 _gtk_tree_view_set_size (GtkTreeView *tree_view,
2754 GtkTreeViewColumn *column;
2757 if (tree_view->priv->model == NULL)
2759 tree_view->priv->width = 1;
2760 tree_view->priv->height = 1;
2766 for (list = tree_view->priv->column, i = 0; list; list = list->next, i++)
2768 column = list->data;
2769 if (!column->visible)
2771 width += TREE_VIEW_COLUMN_SIZE (column);
2775 height = tree_view->priv->tree->root->offset + TREE_VIEW_VERTICAL_SEPERATOR;
2777 tree_view->priv->width = width;
2778 tree_view->priv->height = height;
2780 if (tree_view->priv->hadjustment->upper != tree_view->priv->width)
2782 tree_view->priv->hadjustment->upper = tree_view->priv->width;
2783 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
2786 if (tree_view->priv->vadjustment->upper != tree_view->priv->height)
2788 tree_view->priv->vadjustment->upper = tree_view->priv->height;
2789 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
2792 if (GTK_WIDGET_REALIZED (tree_view))
2794 gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
2795 gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
2797 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
2800 /* this function returns the new width of the column being resized given
2801 * the column and x position of the cursor; the x cursor position is passed
2802 * in as a pointer and automagicly corrected if it's beyond min/max limits */
2804 gtk_tree_view_new_column_width (GtkTreeView *tree_view,
2808 GtkTreeViewColumn *column;
2811 /* first translate the x position from widget->window
2812 * to clist->clist_window */
2814 column = g_list_nth (tree_view->priv->column, i)->data;
2815 width = *x - column->button->allocation.x;
2817 /* Clamp down the value */
2818 if (column->min_width == -1)
2819 width = MAX (column->button->requisition.width,
2822 width = MAX (column->min_width,
2824 if (column->max_width != -1)
2825 width = MIN (width, column->max_width != -1);
2826 *x = column->button->allocation.x + width;
2833 gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
2834 GtkTreeView *tree_view)
2836 if (GTK_WIDGET_REALIZED (tree_view))
2838 gdk_window_move (tree_view->priv->bin_window,
2839 - tree_view->priv->hadjustment->value,
2840 - tree_view->priv->vadjustment->value);
2841 gdk_window_move (tree_view->priv->header_window,
2842 - tree_view->priv->hadjustment->value,
2845 gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
2846 gdk_window_process_updates (tree_view->priv->header_window, TRUE);
2856 * gtk_tree_view_new:
2859 * Creates a new #GtkTreeView widget.
2861 * Return value: A newly created #GtkTreeView widget.
2864 gtk_tree_view_new (void)
2866 GtkTreeView *tree_view;
2868 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
2870 return GTK_WIDGET (tree_view);
2874 * gtk_tree_view_new_with_model:
2875 * @model: the model.
2877 * Creates a new #GtkTreeView widget with the model initialized to @model.
2879 * Return value: A newly created #GtkTreeView widget.
2882 gtk_tree_view_new_with_model (GtkTreeModel *model)
2884 GtkTreeView *tree_view;
2886 tree_view = GTK_TREE_VIEW (gtk_type_new (gtk_tree_view_get_type ()));
2887 gtk_tree_view_set_model (tree_view, model);
2889 return GTK_WIDGET (tree_view);
2893 * gtk_tree_view_get_model:
2894 * @tree_view: a #GtkTreeView
2896 * Returns the model the the #GtkTreeView is based on. Returns NULL if the
2899 * Return value: A #GtkTreeModel, or NULL if none is currently being used.
2902 gtk_tree_view_get_model (GtkTreeView *tree_view)
2904 g_return_val_if_fail (tree_view != NULL, NULL);
2905 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
2907 return tree_view->priv->model;
2911 gtk_tree_view_set_model_realized (GtkTreeView *tree_view)
2916 tree_view->priv->tree = _gtk_rbtree_new ();
2918 gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
2920 gtk_tree_view_node_changed,
2922 gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
2924 gtk_tree_view_node_inserted,
2926 gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
2927 "node_child_toggled",
2928 gtk_tree_view_node_child_toggled,
2930 gtk_signal_connect (GTK_OBJECT (tree_view->priv->model),
2932 gtk_tree_view_node_deleted,
2935 if (tree_view->priv->column == NULL)
2938 path = gtk_tree_path_new_root ();
2942 node = gtk_tree_model_get_node (tree_view->priv->model, path);
2943 gtk_tree_path_free (path);
2944 gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, node, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
2946 gtk_tree_view_create_buttons (tree_view);
2947 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
2951 * gtk_tree_view_set_model:
2952 * @tree_view: A #GtkTreeNode.
2953 * @model: The model.
2955 * Sets the model for a #GtkTreeView. If the @tree_view already has a model
2956 * set, it will remove it before setting the new model. If @model is NULL, then
2957 * it will unset the old model.
2960 gtk_tree_view_set_model (GtkTreeView *tree_view,
2961 GtkTreeModel *model)
2964 GtkTreeViewColumn *column;
2966 g_return_if_fail (tree_view != NULL);
2967 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
2969 if (tree_view->priv->model != NULL)
2971 for (list = tree_view->priv->column; list; list = list->next)
2973 column = list->data;
2976 gtk_widget_unparent (column->button);
2977 gdk_window_set_user_data (column->window, NULL);
2978 gdk_window_destroy (column->window);
2981 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_MODEL_SETUP))
2983 gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
2984 gtk_tree_view_node_changed,
2986 gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
2987 gtk_tree_view_node_inserted,
2989 gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
2990 gtk_tree_view_node_child_toggled,
2992 gtk_signal_disconnect_by_func (GTK_OBJECT (tree_view->priv->model),
2993 gtk_tree_view_node_deleted,
2995 _gtk_rbtree_free (tree_view->priv->tree);
2998 g_list_free (tree_view->priv->column);
2999 tree_view->priv->column = NULL;
3000 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_MODEL_SETUP);
3003 tree_view->priv->model = model;
3006 tree_view->priv->tree = NULL;
3007 tree_view->priv->columns = 0;
3008 tree_view->priv->column = NULL;
3009 if (GTK_WIDGET_REALIZED (tree_view))
3010 _gtk_tree_view_set_size (tree_view, 0, 0);
3014 if (GTK_WIDGET_REALIZED (tree_view))
3016 gtk_tree_view_set_model_realized (tree_view);
3017 _gtk_tree_view_set_size (tree_view, -1, -1);
3022 * gtk_tree_view_get_selection:
3023 * @tree_view: A #GtkTreeView.
3025 * Gets the #GtkTreeSelection associated with @tree_view.
3027 * Return value: A #GtkTreeSelection object.
3030 gtk_tree_view_get_selection (GtkTreeView *tree_view)
3032 g_return_val_if_fail (tree_view != NULL, NULL);
3033 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3035 if (tree_view->priv->selection == NULL)
3036 gtk_tree_selection_new_with_tree_view (tree_view);
3038 return tree_view->priv->selection;
3042 * gtk_tree_view_get_hadjustment:
3043 * @tree_view: A #GtkTreeView
3045 * Gets the #GtkAdjustment currently being used for the horizontal aspect.
3047 * Return value: A #GtkAdjustment object, or NULL if none is currently being
3051 gtk_tree_view_get_hadjustment (GtkTreeView *tree_view)
3053 g_return_val_if_fail (tree_view != NULL, NULL);
3054 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3056 return tree_view->priv->hadjustment;
3060 * gtk_tree_view_set_hadjustment:
3061 * @tree_view: A #GtkTreeView
3062 * @adjustment: The #GtkAdjustment to set, or NULL
3064 * Sets the #GtkAdjustment for the current horizontal aspect.
3067 gtk_tree_view_set_hadjustment (GtkTreeView *tree_view,
3068 GtkAdjustment *adjustment)
3070 g_return_if_fail (tree_view != NULL);
3071 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3073 gtk_tree_view_set_adjustments (tree_view,
3075 tree_view->priv->vadjustment);
3079 * gtk_tree_view_get_vadjustment:
3080 * @tree_view: A #GtkTreeView
3082 * Gets the #GtkAdjustment currently being used for the vertical aspect.
3084 * Return value: A #GtkAdjustment object, or NULL if none is currently being
3088 gtk_tree_view_get_vadjustment (GtkTreeView *tree_view)
3090 g_return_val_if_fail (tree_view != NULL, NULL);
3091 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3093 return tree_view->priv->vadjustment;
3097 * gtk_tree_view_set_vadjustment:
3098 * @tree_view: A #GtkTreeView
3099 * @adjustment: The #GtkAdjustment to set, or NULL
3101 * Sets the #GtkAdjustment for the current vertical aspect.
3104 gtk_tree_view_set_vadjustment (GtkTreeView *tree_view,
3105 GtkAdjustment *adjustment)
3107 g_return_if_fail (tree_view != NULL);
3108 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3110 gtk_tree_view_set_adjustments (tree_view,
3111 tree_view->priv->hadjustment,
3116 * gtk_tree_view_set_adjustments:
3117 * @tree_view: A #GtkTreeView
3118 * @hadj: The horizontal #GtkAdjustment to set, or NULL
3119 * @vadj: The vertical #GtkAdjustment to set, or NULL
3121 * Sets the horizonal and or vertical #GtkAdjustment.
3124 gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
3125 GtkAdjustment *hadj,
3126 GtkAdjustment *vadj)
3128 gboolean need_adjust = FALSE;
3130 g_return_if_fail (tree_view != NULL);
3131 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3134 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
3136 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3138 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
3140 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
3142 if (tree_view->priv->hadjustment && (tree_view->priv->hadjustment != hadj))
3144 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->hadjustment), tree_view);
3145 gtk_object_unref (GTK_OBJECT (tree_view->priv->hadjustment));
3148 if (tree_view->priv->vadjustment && (tree_view->priv->vadjustment != vadj))
3150 gtk_signal_disconnect_by_data (GTK_OBJECT (tree_view->priv->vadjustment), tree_view);
3151 gtk_object_unref (GTK_OBJECT (tree_view->priv->vadjustment));
3154 if (tree_view->priv->hadjustment != hadj)
3156 tree_view->priv->hadjustment = hadj;
3157 gtk_object_ref (GTK_OBJECT (tree_view->priv->hadjustment));
3158 gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
3160 gtk_signal_connect (GTK_OBJECT (tree_view->priv->hadjustment), "value_changed",
3161 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
3166 if (tree_view->priv->vadjustment != vadj)
3168 tree_view->priv->vadjustment = vadj;
3169 gtk_object_ref (GTK_OBJECT (tree_view->priv->vadjustment));
3170 gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
3172 gtk_signal_connect (GTK_OBJECT (tree_view->priv->vadjustment), "value_changed",
3173 (GtkSignalFunc) gtk_tree_view_adjustment_changed,
3179 gtk_tree_view_adjustment_changed (NULL, tree_view);
3183 /* Column and header operations */
3186 * gtk_tree_view_get_headers_visible:
3187 * @tree_view: A #GtkTreeView.
3189 * Returns TRUE if the headers on the @tree_view are visible.
3191 * Return value: whether the headers are visible or not.
3194 gtk_tree_view_get_headers_visible (GtkTreeView *tree_view)
3196 g_return_val_if_fail (tree_view != NULL, FALSE);
3197 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
3199 return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3203 * gtk_tree_view_set_headers_visible:
3204 * @tree_view: A #GtkTreeView.
3205 * @headers_visible: TRUE if the headers are visible
3207 * Sets the the visibility state of the headers.
3210 gtk_tree_view_set_headers_visible (GtkTreeView *tree_view,
3211 gboolean headers_visible)
3215 GtkTreeViewColumn *column;
3217 g_return_if_fail (tree_view != NULL);
3218 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3220 if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) == headers_visible)
3223 if (headers_visible)
3224 GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3226 GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE);
3228 if (GTK_WIDGET_REALIZED (tree_view))
3230 gdk_window_get_position (tree_view->priv->bin_window, &x, &y);
3231 if (headers_visible)
3233 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
3234 for (list = tree_view->priv->column; list; list = list->next)
3236 column = list->data;
3237 gtk_widget_map (column->button);
3240 for (list = tree_view->priv->column; list; list = list->next)
3242 column = list->data;
3243 if (column->visible == FALSE)
3245 if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
3247 gdk_window_raise (column->window);
3248 gdk_window_show (column->window);
3251 gdk_window_hide (column->window);
3253 gdk_window_show (tree_view->priv->header_window);
3257 gdk_window_move_resize (tree_view->priv->bin_window, x, y, tree_view->priv->width, tree_view->priv->height);
3258 for (list = tree_view->priv->column; list; list = list->next)
3260 column = list->data;
3261 gtk_widget_unmap (column->button);
3263 gdk_window_hide (tree_view->priv->header_window);
3267 tree_view->priv->vadjustment->page_size = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
3268 tree_view->priv->vadjustment->page_increment = (GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view)) / 2;
3269 tree_view->priv->vadjustment->lower = 0;
3270 tree_view->priv->vadjustment->upper = tree_view->priv->height;
3271 gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
3273 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3278 * gtk_tree_view_columns_autosize:
3279 * @tree_view: A #GtkTreeView.
3281 * Resizes all columns to their optimal width.
3284 gtk_tree_view_columns_autosize (GtkTreeView *tree_view)
3286 gboolean dirty = FALSE;
3288 GtkTreeViewColumn *column;
3290 g_return_if_fail (tree_view != NULL);
3291 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3293 for (list = tree_view->priv->column; list; list = list->next)
3295 column = list->data;
3296 if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
3298 column->dirty = TRUE;
3303 gtk_widget_queue_resize (GTK_WIDGET (tree_view));
3307 * gtk_tree_view_set_headers_active:
3308 * @tree_view: A #GtkTreeView.
3309 * @active: TRUE if the columns are active.
3311 * Sets the headers active (eg. keyboard navigable) or inactive.
3314 gtk_tree_view_set_headers_active (GtkTreeView *tree_view,
3319 g_return_if_fail (tree_view != NULL);
3320 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3321 g_return_if_fail (tree_view->priv->model != NULL);
3323 for (list = tree_view->priv->column; list; list = list->next)
3324 gtk_tree_view_column_set_header_active (GTK_TREE_VIEW_COLUMN (list->data), active);
3328 * gtk_tree_view_append_column:
3329 * @tree_view: A #GtkTreeView.
3330 * @column: The #GtkTreeViewColumn to add.
3332 * Appends @column to the list of columns.
3334 * Return value: The number of columns in @tree_view.
3337 gtk_tree_view_append_column (GtkTreeView *tree_view,
3338 GtkTreeViewColumn *column)
3340 g_return_val_if_fail (tree_view != NULL, -1);
3341 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3342 g_return_val_if_fail (column != NULL, -1);
3343 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3344 g_return_val_if_fail (column->tree_view == NULL, -1);
3346 tree_view->priv->column = g_list_append (tree_view->priv->column,
3348 column->tree_view = GTK_WIDGET (tree_view);
3349 return tree_view->priv->columns++;
3354 * gtk_tree_view_remove_column:
3355 * @tree_view: A #GtkTreeView.
3356 * @column: The #GtkTreeViewColumn to remove.
3358 * Removes @column from @tree_view.
3360 * Return value: The number of columns in @tree_view.
3363 gtk_tree_view_remove_column (GtkTreeView *tree_view,
3364 GtkTreeViewColumn *column)
3366 g_return_val_if_fail (tree_view != NULL, -1);
3367 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3368 g_return_val_if_fail (column != NULL, -1);
3369 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3370 g_return_val_if_fail (column->tree_view == tree_view, -1);
3372 tree_view->priv->column = g_list_remove (tree_view->priv->column,
3374 column->tree_view = NULL;
3375 g_object_unref (column);
3377 return tree_view->priv->columns--;
3382 * gtk_tree_view_insert_column:
3383 * @tree_view: A #GtkTreeView.
3384 * @column: The #GtkTreeViewColumn to be inserted.
3385 * @position: The position to insert @column in.
3387 * This inserts the @column into the @tree_view at @position.
3389 * Return value: The number of columns in @tree_view.
3392 gtk_tree_view_insert_column (GtkTreeView *tree_view,
3393 GtkTreeViewColumn *column,
3396 g_return_val_if_fail (tree_view != NULL, -1);
3397 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
3398 g_return_val_if_fail (column != NULL, -1);
3399 g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
3400 g_return_val_if_fail (column->tree_view == NULL, -1);
3402 tree_view->priv->column = g_list_insert (tree_view->priv->column,
3404 column->tree_view = GTK_WIDGET (tree_view);
3405 return tree_view->priv->columns++;
3409 * gtk_tree_view_get_column:
3410 * @tree_view: A #GtkTreeView.
3411 * @n: The position of the column, counting from 0.
3413 * Gets the #GtkTreeViewColumn at the given position in the #tree_view.
3415 * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
3419 gtk_tree_view_get_column (GtkTreeView *tree_view,
3422 g_return_val_if_fail (tree_view != NULL, NULL);
3423 g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
3424 g_return_val_if_fail (tree_view->priv->model != NULL, NULL);
3425 g_return_val_if_fail (n >= 0 || n < tree_view->priv->columns, NULL);
3427 if (tree_view->priv->column == NULL)
3430 return GTK_TREE_VIEW_COLUMN (g_list_nth (tree_view->priv->column, n)->data);
3434 * gtk_tree_view_move_to:
3435 * @tree_view: A #GtkTreeView.
3436 * @path: The path of the row to move to.
3437 * @column: The #GtkTreeViewColumn to move horizontally to.
3438 * @row_align: The vertical alignment of the row specified by @path.
3439 * @col_align: The horizontal alignment of the column specified by @column.
3441 * Moves the alignments of @tree_view to the position specified by @column and
3442 * @path. If @column is NULL, then the first visible column is assumed, and the
3443 * @tree_view is left justified. Likewise, if @path is NULL the first row is
3444 * assumed, and the @tree_view is top justified. @row_align determines where
3445 * the @row is placed, and @col_align determines where @column is placed. Both
3446 * are expected to be between 0.0 and 1.0.
3449 gtk_tree_view_move_to (GtkTreeView *tree_view,
3451 GtkTreeViewColumn *column,
3455 GtkRBNode *node = NULL;
3456 GtkRBTree *tree = NULL;
3458 g_return_if_fail (tree_view != NULL);
3459 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3461 row_align = CLAMP (row_align, 0, 1);
3462 col_align = CLAMP (col_align, 0, 1);
3466 _gtk_tree_view_find_node (tree_view, path,
3468 /* Should we justify it to the bottom? */
3473 if (tree_view->priv->hadjustment && column >= 0)
3475 GtkTreeViewColumn *col;
3477 col = g_list_nth (tree_view->priv->column, column)->data;
3478 /* FIXME -- write */
3483 gtk_tree_view_expand_all_helper (GtkRBTree *tree,
3487 GtkTreeView *tree_view = data;
3490 _gtk_rbtree_traverse (node->children,
3491 node->children->root,
3493 gtk_tree_view_expand_all_helper,
3495 else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
3498 GtkTreeNode tree_node;
3500 node->children = _gtk_rbtree_new ();
3501 node->children->parent_tree = tree;
3502 node->children->parent_node = node;
3503 path = _gtk_tree_view_find_path (tree_view, tree, node);
3504 tree_node = gtk_tree_model_get_node (tree_view->priv->model, path);
3505 tree_node = gtk_tree_model_node_children (tree_view->priv->model, tree_node);
3506 gtk_tree_view_build_tree (tree_view,
3509 gtk_tree_path_get_depth (path) + 1,
3511 GTK_WIDGET_REALIZED (tree_view));
3512 gtk_tree_path_free (path);
3517 * gtk_tree_view_expand_all:
3518 * @tree_view: A #GtkTreeView.
3520 * Recursively expands all nodes in the @tree_view.
3523 gtk_tree_view_expand_all (GtkTreeView *tree_view)
3525 g_return_if_fail (tree_view != NULL);
3526 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3527 g_return_if_fail (tree_view->priv->tree != NULL);
3529 _gtk_rbtree_traverse (tree_view->priv->tree,
3530 tree_view->priv->tree->root,
3532 gtk_tree_view_expand_all_helper,
3535 _gtk_tree_view_set_size (tree_view, -1,-1);
3539 gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
3546 GtkTreeNode tree_node;
3548 path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
3550 node->children->root);
3551 tree_node = gtk_tree_model_get_node (GTK_TREE_VIEW (data)->priv->model, path);
3552 gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
3555 gtk_tree_path_get_depth (path));
3556 _gtk_rbtree_remove (node->children);
3557 gtk_tree_path_free (path);
3562 * gtk_tree_view_collapse_all:
3563 * @tree_view: A #GtkTreeView.
3565 * Recursively collapses all visible, expanded nodes in @tree_view.
3568 gtk_tree_view_collapse_all (GtkTreeView *tree_view)
3570 g_return_if_fail (tree_view != NULL);
3571 g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
3572 g_return_if_fail (tree_view->priv->tree != NULL);
3574 _gtk_rbtree_traverse (tree_view->priv->tree,
3575 tree_view->priv->tree->root,
3577 gtk_tree_view_collapse_all_helper,
3580 if (GTK_WIDGET_REALIZED (tree_view))
3581 gtk_widget_queue_draw (GTK_WIDGET (tree_view));