GdkEventButton *event);
static gboolean gtk_tree_view_button_release (GtkWidget *widget,
GdkEventButton *event);
+static gboolean gtk_tree_view_grab_broken (GtkWidget *widget,
+ GdkEventGrabBroken *event);
#if 0
static gboolean gtk_tree_view_configure (GtkWidget *widget,
GdkEventConfigure *event);
GtkStyle *previous_style);
static void gtk_tree_view_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
+static void gtk_tree_view_state_changed (GtkWidget *widget,
+ GtkStateType previous_state);
/* container signals */
static void gtk_tree_view_remove (GtkContainer *container,
GtkTreePath *path);
static void validate_visible_area (GtkTreeView *tree_view);
static gboolean validate_rows_handler (GtkTreeView *tree_view);
+static gboolean do_validate_rows (GtkTreeView *tree_view,
+ gboolean size_request);
static gboolean validate_rows (GtkTreeView *tree_view);
static gboolean presize_handler_callback (gpointer data);
static void install_presize_handler (GtkTreeView *tree_view);
static gboolean gtk_tree_view_search_button_press_event (GtkWidget *widget,
GdkEventButton *event,
GtkTreeView *tree_view);
+static gboolean gtk_tree_view_search_scroll_event (GtkWidget *entry,
+ GdkEventScroll *event,
+ GtkTreeView *tree_view);
static gboolean gtk_tree_view_search_key_press_event (GtkWidget *entry,
GdkEventKey *event,
GtkTreeView *tree_view);
};
tree_view_type =
- g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView",
+ g_type_register_static (GTK_TYPE_CONTAINER, I_("GtkTreeView"),
&tree_view_info, 0);
}
widget_class->size_allocate = gtk_tree_view_size_allocate;
widget_class->button_press_event = gtk_tree_view_button_press;
widget_class->button_release_event = gtk_tree_view_button_release;
+ widget_class->grab_broken_event = gtk_tree_view_grab_broken;
/*widget_class->configure_event = gtk_tree_view_configure;*/
widget_class->motion_notify_event = gtk_tree_view_motion;
widget_class->expose_event = gtk_tree_view_expose;
widget_class->grab_focus = gtk_tree_view_grab_focus;
widget_class->style_set = gtk_tree_view_style_set;
widget_class->grab_notify = gtk_tree_view_grab_notify;
+ widget_class->state_changed = gtk_tree_view_state_changed;
/* GtkContainer signals */
container_class->remove = gtk_tree_view_remove;
/* Signals */
widget_class->set_scroll_adjustments_signal =
- g_signal_new ("set_scroll_adjustments",
+ g_signal_new (I_("set_scroll_adjustments"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
GTK_TYPE_ADJUSTMENT,
GTK_TYPE_ADJUSTMENT);
+ /**
+ * GtkTreeView::row-activated:
+ * @tree_view: the object on which the signal is emitted
+ * @path: the #GtkTreePath for the activated row
+ * @column: the #GtkTreeViewColumn in which the activation occurred
+ *
+ * The "row-activated" signal is emitted when the method
+ * gtk_tree_view_row_activated() is called or the user double clicks
+ * a treeview row. It is also emitted when a non-editable row is
+ * selected and one of the keys: Space, Shift+Space, Return or
+ * Enter is pressed.
+ *
+ * For selection handling refer to the <link linkend="TreeWidget">tree
+ * widget conceptual overview</link> as well as #GtkTreeSelection.
+ */
tree_view_signals[ROW_ACTIVATED] =
- g_signal_new ("row_activated",
+ g_signal_new (I_("row_activated"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, row_activated),
GTK_TYPE_TREE_VIEW_COLUMN);
tree_view_signals[TEST_EXPAND_ROW] =
- g_signal_new ("test_expand_row",
+ g_signal_new (I_("test_expand_row"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
GTK_TYPE_TREE_PATH);
tree_view_signals[TEST_COLLAPSE_ROW] =
- g_signal_new ("test_collapse_row",
+ g_signal_new (I_("test_collapse_row"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
GTK_TYPE_TREE_PATH);
tree_view_signals[ROW_EXPANDED] =
- g_signal_new ("row_expanded",
+ g_signal_new (I_("row_expanded"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
GTK_TYPE_TREE_PATH);
tree_view_signals[ROW_COLLAPSED] =
- g_signal_new ("row_collapsed",
+ g_signal_new (I_("row_collapsed"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
GTK_TYPE_TREE_PATH);
tree_view_signals[COLUMNS_CHANGED] =
- g_signal_new ("columns_changed",
+ g_signal_new (I_("columns_changed"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
G_TYPE_NONE, 0);
tree_view_signals[CURSOR_CHANGED] =
- g_signal_new ("cursor_changed",
+ g_signal_new (I_("cursor_changed"),
G_TYPE_FROM_CLASS (o_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
G_TYPE_NONE, 0);
tree_view_signals[MOVE_CURSOR] =
- g_signal_new ("move_cursor",
+ g_signal_new (I_("move_cursor"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
G_TYPE_INT);
tree_view_signals[SELECT_ALL] =
- g_signal_new ("select_all",
+ g_signal_new (I_("select_all"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
G_TYPE_BOOLEAN, 0);
tree_view_signals[UNSELECT_ALL] =
- g_signal_new ("unselect_all",
+ g_signal_new (I_("unselect_all"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
G_TYPE_BOOLEAN, 0);
tree_view_signals[SELECT_CURSOR_ROW] =
- g_signal_new ("select_cursor_row",
+ g_signal_new (I_("select_cursor_row"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
G_TYPE_BOOLEAN);
tree_view_signals[TOGGLE_CURSOR_ROW] =
- g_signal_new ("toggle_cursor_row",
+ g_signal_new (I_("toggle_cursor_row"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
G_TYPE_BOOLEAN, 0);
tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
- g_signal_new ("expand_collapse_cursor_row",
+ g_signal_new (I_("expand_collapse_cursor_row"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
G_TYPE_BOOLEAN);
tree_view_signals[SELECT_CURSOR_PARENT] =
- g_signal_new ("select_cursor_parent",
+ g_signal_new (I_("select_cursor_parent"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
G_TYPE_BOOLEAN, 0);
tree_view_signals[START_INTERACTIVE_SEARCH] =
- g_signal_new ("start_interactive_search",
+ g_signal_new (I_("start_interactive_search"),
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, GDK_CONTROL_MASK, "select_cursor_parent", 0);
gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "start_interactive_search", 0);
gtk_binding_entry_add_signal (binding_set, GDK_F, GDK_CONTROL_MASK, "start_interactive_search", 0);
+
+ g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
}
static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
- tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
+ tree_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (tree_view, GTK_TYPE_TREE_VIEW, GtkTreeViewPrivate);
+
GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
case PROP_HEADERS_VISIBLE:
g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
break;
+ case PROP_HEADERS_CLICKABLE:
+ g_value_set_boolean (value, gtk_tree_view_get_headers_clickable (tree_view));
+ break;
case PROP_EXPANDER_COLUMN:
g_value_set_object (value, tree_view->priv->expander_column);
break;
static void
gtk_tree_view_finalize (GObject *object)
{
- GtkTreeView *tree_view = (GtkTreeView *) object;
-
- g_free (tree_view->priv);
-
(* G_OBJECT_CLASS (parent_class)->finalize) (object);
}
/* GtkObject Methods
*/
+static void
+gtk_tree_view_free_rbtree (GtkTreeView *tree_view)
+{
+ _gtk_rbtree_free (tree_view->priv->tree);
+
+ tree_view->priv->tree = NULL;
+ tree_view->priv->button_pressed_node = NULL;
+ tree_view->priv->button_pressed_tree = NULL;
+ tree_view->priv->prelight_tree = NULL;
+ tree_view->priv->prelight_node = NULL;
+ tree_view->priv->expanded_collapsed_node = NULL;
+ tree_view->priv->expanded_collapsed_tree = NULL;
+}
+
static void
gtk_tree_view_destroy (GtkObject *object)
{
if (tree_view->priv->tree != NULL)
{
gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
- _gtk_rbtree_free (tree_view->priv->tree);
- tree_view->priv->tree = NULL;
+
+ gtk_tree_view_free_rbtree (tree_view);
}
if (tree_view->priv->selection != NULL)
}
}
- if (tree_view->priv->search_destroy)
+ if (tree_view->priv->search_destroy && tree_view->priv->search_user_data)
{
(* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
tree_view->priv->search_user_data = NULL;
}
- if (tree_view->priv->row_separator_destroy)
+ if (tree_view->priv->row_separator_destroy && tree_view->priv->row_separator_data)
{
(* tree_view->priv->row_separator_destroy) (tree_view->priv->row_separator_data);
tree_view->priv->row_separator_data = NULL;
{
GList *tmp_list;
GtkTreeView *tree_view;
- GdkGCValues values;
GdkWindowAttr attributes;
gint attributes_mask;
&attributes, attributes_mask);
gdk_window_set_user_data (tree_view->priv->header_window, widget);
-
- values.foreground = (widget->style->white.pixel==0 ?
- widget->style->black:widget->style->white);
- values.function = GDK_XOR;
- values.subwindow_mode = GDK_INCLUDE_INFERIORS;
-
/* Add them all up. */
widget->style = gtk_style_attach (widget->style, widget->window);
gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
* sure we have some size. In practice, with a lot of static lists, this
* should get a good width.
*/
- validate_rows (tree_view);
+ do_validate_rows (tree_view, FALSE);
gtk_tree_view_size_request_columns (tree_view);
gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
gint extra, extra_per_column;
gint full_requested_width = 0;
gint number_of_expand_columns = 0;
+ gboolean column_changed = FALSE;
gboolean rtl;
tree_view = GTK_TREE_VIEW (widget);
width += column->width;
if (column->width > old_width)
- invalidate_column (tree_view, column);
+ column_changed = TRUE;
gtk_widget_size_allocate (column->button, &allocation);
allocation.y,
TREE_VIEW_DRAG_WIDTH, allocation.height);
}
+
+ if (column_changed)
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
}
GList *tmp_list;
GtkTreeView *tree_view;
gboolean width_changed = FALSE;
- gboolean dy_changed = FALSE;
gint old_width = widget->allocation.width;
g_return_if_fail (GTK_IS_TREE_VIEW (widget));
tree_view->priv->vadjustment->lower = 0;
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
- if (tree_view->priv->vadjustment->value + allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view) > tree_view->priv->height)
- {
- double before = tree_view->priv->vadjustment->value;
- gtk_adjustment_set_value (tree_view->priv->vadjustment,
- MAX (tree_view->priv->height - tree_view->priv->vadjustment->page_size, 0));
- if (before != tree_view->priv->vadjustment->value)
- dy_changed = TRUE;
- }
-
gtk_adjustment_changed (tree_view->priv->vadjustment);
+
+ /* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
+ if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
+ else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
+ gtk_tree_view_top_row_to_dy (tree_view);
+ else
+ gtk_tree_view_dy_to_top_row (tree_view);
if (GTK_WIDGET_REALIZED (widget))
{
else
gtk_widget_queue_draw (widget);
}
-
- if (dy_changed)
- gtk_widget_queue_draw (widget);
}
}
for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
list; list = (rtl ? list->prev : list->next))
{
- column = list->data;
+ GtkTreeViewColumn *candidate = list->data;
- if (!column->visible)
+ if (!candidate->visible)
continue;
- background_area.width = column->width;
+ background_area.width = candidate->width;
if ((background_area.x > (gint) event->x) ||
(background_area.x + background_area.width <= (gint) event->x))
{
}
/* we found the focus column */
+ column = candidate;
cell_area = background_area;
cell_area.width -= horizontal_separator;
cell_area.height -= vertical_separator;
if (event->type == GDK_2BUTTON_PRESS &&
gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
{
+ column->use_resized_width = FALSE;
_gtk_tree_view_column_autosize (tree_view, column);
return TRUE;
}
gtk_grab_add (widget);
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
column->resized_width = column->width;
- column->use_resized_width = TRUE;
/* block attached dnd signal handler */
drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
{
GtkTreeView *tree_view;
gpointer drag_data;
- gint x;
- gint i;
tree_view = GTK_TREE_VIEW (widget);
- i = tree_view->priv->drag_pos;
tree_view->priv->drag_pos = -1;
- /* unblock attached dnd signal handler */
+ /* unblock attached dnd signal handler */
drag_data = g_object_get_data (G_OBJECT (widget), "gtk-site-data");
if (drag_data)
g_signal_handlers_unblock_matched (widget,
drag_data);
GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
- gtk_widget_get_pointer (widget, &x, NULL);
gtk_grab_remove (widget);
gdk_display_pointer_ungrab (gdk_drawable_get_display (event->window),
event->time);
return TRUE;
}
+static gboolean
+gtk_tree_view_grab_broken (GtkWidget *widget,
+ GdkEventGrabBroken *event)
+{
+ GtkTreeView *tree_view;
+
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
+ g_return_val_if_fail (event != NULL, FALSE);
+
+ tree_view = GTK_TREE_VIEW (widget);
+
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
+ gtk_tree_view_button_release_drag_column (widget, (GdkEventButton *)event);
+
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE))
+ gtk_tree_view_button_release_column_resize (widget, (GdkEventButton *)event);
+
+ return TRUE;
+}
+
#if 0
static gboolean
gtk_tree_view_configure (GtkWidget *widget,
new_width = gtk_tree_view_new_column_width (tree_view,
tree_view->priv->drag_pos, &x);
if (x != tree_view->priv->x_drag &&
- (new_width != column->fixed_width));
+ (new_width != column->fixed_width))
{
+ column->use_resized_width = TRUE;
column->resized_width = new_width;
gtk_widget_queue_resize (widget);
}
GtkRBTree *drag_highlight_tree = NULL;
GtkTreeIter iter;
gint new_y;
- gint y_offset, x_offset, cell_offset;
+ gint y_offset, cell_offset;
gint max_height;
gint depth;
GdkRectangle background_area;
guint flags;
gint highlight_x;
gint bin_window_width;
+ gint bin_window_height;
GtkTreePath *cursor_path;
GtkTreePath *drag_dest_path;
GList *last_column;
gboolean has_special_cell;
gboolean rtl;
gint n_visible_columns;
+ gint pointer_x, pointer_y;
+ gboolean got_pointer = FALSE;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
if (new_y < 0)
new_y = 0;
y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
+ gdk_drawable_get_size (tree_view->priv->bin_window,
+ &bin_window_width, &bin_window_height);
+
+ if (tree_view->priv->height < bin_window_height)
+ {
+ gtk_paint_flat_box (widget->style,
+ event->window,
+ widget->state,
+ GTK_SHADOW_NONE,
+ &event->area,
+ widget,
+ "cell_even",
+ 0, tree_view->priv->height,
+ bin_window_width, bin_window_height);
+ }
if (node == NULL)
return TRUE;
_gtk_tree_view_find_node (tree_view, drag_dest_path,
&drag_highlight_tree, &drag_highlight);
- gdk_drawable_get_size (tree_view->priv->bin_window,
- &bin_window_width, NULL);
-
n_visible_columns = 0;
for (list = tree_view->priv->columns; list; list = list->next)
max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
- x_offset = -event->area.x;
cell_offset = 0;
highlight_x = 0; /* should match x coord of first cell */
parity = _gtk_rbtree_node_find_parity (tree, node);
+ /* we *need* to set cell data on all cells before the call
+ * to _has_special_cell, else _has_special_cell() does not
+ * return a correct value.
+ */
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
+ {
+ GtkTreeViewColumn *column = list->data;
+ gtk_tree_view_column_cell_set_cell_data (column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
+ node->children?TRUE:FALSE);
+ }
+
has_special_cell = gtk_tree_view_has_special_cell (tree_view);
for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
g_assert (detail);
- if (flags & GTK_CELL_RENDERER_SELECTED)
+ if (widget->state == GTK_STATE_INSENSITIVE)
+ state = GTK_STATE_INSENSITIVE;
+ else if (flags & GTK_CELL_RENDERER_SELECTED)
state = GTK_STATE_SELECTED;
else
state = GTK_STATE_NORMAL;
flags);
if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
- gint x, y;
- gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
+ if (!got_pointer)
+ {
+ gdk_window_get_pointer (tree_view->priv->bin_window,
+ &pointer_x, &pointer_y, NULL);
+ got_pointer = TRUE;
+ }
+
gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
- tree,
+ tree,
node,
- x, y);
+ pointer_x, pointer_y);
}
}
else
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
gint width;
- gint focus_line_width;
switch (tree_view->priv->drag_dest_pos)
{
break;
gdk_drawable_get_size (tree_view->priv->bin_window,
&width, NULL);
- gtk_widget_style_get (widget, "focus-line-width", &focus_line_width, NULL);
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
GTK_WIDGET_STATE (widget),
continue;
}
- return cur_column;
+ return left_column;
}
if (!tree_view->priv->column_drop_func)
continue;
}
- return cur_column;
+ return left_column;
}
if (!tree_view->priv->column_drop_func)
return TRUE;
}
- if (tree_view->priv->columns && (event->state & GDK_SHIFT_MASK)
- && (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
- || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
+ if (tree_view->priv->columns &&
+ (event->state & GDK_SHIFT_MASK) && (event->state & GDK_MOD1_MASK) &&
+ (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
+ || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
{
list = tree_view->priv->columns;
while (list)
}
}
- if (tree_view->priv->columns && (event->state & GDK_CONTROL_MASK) &&
+ if (tree_view->priv->columns && (event->state & GDK_MOD1_MASK) &&
(event->keyval == GDK_Left || event->keyval == GDK_KP_Left
|| event->keyval == GDK_Right || event->keyval == GDK_KP_Right
|| event->keyval == GDK_Home || event->keyval == GDK_KP_Home
/* Make a copy of the current text */
old_text = g_strdup (gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry)));
new_event = gdk_event_copy ((GdkEvent *) event);
- ((GdkEventKey *) new_event)->window = tree_view->priv->search_entry->window;
+ g_object_unref (((GdkEventKey *) new_event)->window);
+ ((GdkEventKey *) new_event)->window = g_object_ref (tree_view->priv->search_window->window);
gtk_widget_realize (tree_view->priv->search_window);
popup_menu_id = g_signal_connect (tree_view->priv->search_entry,
/* Send the event to the window. If the preedit_changed signal is emitted
* during this event, we will set priv->imcontext_changed */
tree_view->priv->imcontext_changed = FALSE;
- retval = gtk_widget_event (tree_view->priv->search_entry, new_event);
+ retval = gtk_widget_event (tree_view->priv->search_window, new_event);
+ gdk_event_free (new_event);
gtk_widget_hide (tree_view->priv->search_window);
g_signal_handler_disconnect (tree_view->priv->search_entry,
GList *list;
gint height = 0;
gint horizontal_separator;
+ gint vertical_separator;
+ gint focus_line_width;
gint depth = gtk_tree_path_get_depth (path);
gboolean retval = FALSE;
gboolean is_separator = FALSE;
gint focus_pad;
-
+
/* double check the row needs validating */
if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
gtk_widget_style_get (GTK_WIDGET (tree_view),
"focus-padding", &focus_pad,
+ "focus-line-width", &focus_line_width,
"horizontal-separator", &horizontal_separator,
+ "vertical-separator", &vertical_separator,
NULL);
for (list = tree_view->priv->columns; list; list = list->next)
if (!is_separator)
{
+ tmp_height += vertical_separator;
height = MAX (height, tmp_height);
height = MAX (height, tree_view->priv->expander_size);
}
path = gtk_tree_row_reference_get_path (tree_view->priv->scroll_to_path);
if (path && !_gtk_tree_view_find_node (tree_view, path, &tree, &node))
{
+ /* we are going to scroll, and will update dy */
+ update_dy = TRUE;
+
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
dy = _gtk_rbtree_node_find_offset (tree, node);
if (dy >= tree_view->priv->vadjustment->value &&
- dy < (tree_view->priv->vadjustment->value
- + tree_view->priv->vadjustment->page_size))
+ dy + height <= (tree_view->priv->vadjustment->value
+ + tree_view->priv->vadjustment->page_size))
{
/* row visible: keep the row at the same position */
area_above = dy - tree_view->priv->vadjustment->value;
above_path = gtk_tree_path_copy (path);
+ /* if we do not validate any row above the new top_row, we will make sure
+ * that the row immediately above top_row has been validated. (if we do not
+ * do this, _gtk_rbtree_find_offset will find the row above top_row, because
+ * when invalidated that row's height will be zero. and this will mess up
+ * scrolling).
+ */
+ if (area_above == 0)
+ {
+ GtkRBTree *tree;
+ GtkRBNode *node;
+ GtkTreePath *tmppath;
+ GtkTreeIter iter;
+
+ _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
+
+ tmppath = gtk_tree_path_copy (above_path);
+
+ _gtk_rbtree_prev_full (tree, node, &tree, &node);
+ if (! gtk_tree_path_prev (tmppath) && node != NULL)
+ {
+ gtk_tree_path_free (tmppath);
+ tmppath = _gtk_tree_view_find_path (tree_view, tree, node);
+ }
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, tmppath);
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ need_redraw = TRUE;
+ if (validate_row (tree_view, tree, node, &iter, path))
+ size_changed = TRUE;
+ }
+
+ gtk_tree_path_free (tmppath);
+ }
+
/* Now, we walk forwards and backwards, measuring rows. Unfortunately,
* backwards is much slower then forward, as there is no iter_prev function.
* We go forwards first in case we run out of tree. Then we go backwards to
update_dy = TRUE;
}
+ /* if we scrolled to a path, we need to set the dy here,
+ * and sync the top row accordingly
+ */
+ if (tree_view->priv->scroll_to_path)
+ {
+ gint dy;
+
+ if (node != NULL)
+ dy = _gtk_rbtree_node_find_offset (tree, node) - area_above;
+ else
+ dy = 0;
+
+ gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
+ gtk_tree_view_dy_to_top_row (tree_view);
+
+ need_redraw = TRUE;
+ }
+ else if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
+ {
+ /* when we are not scrolling, we should never set dy to something
+ * else than zero. we update top_row to be in sync with dy = 0.
+ */
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
+ gtk_tree_view_dy_to_top_row (tree_view);
+ }
+ else
+ gtk_tree_view_top_row_to_dy (tree_view);
+
+ /* update width/height and queue a resize */
if (size_changed)
{
GtkRequisition requisition;
/* We temporarily guess a size, under the assumption that it will be the
* same when we get our next size_allocate. If we don't do this, we'll be
* in an inconsistent state if we call top_row_to_dy. */
+
gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
- /* if we scroll at all, always update dy and kill the top_row */
- if (tree_view->priv->scroll_to_path &&
- ! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
- {
- update_dy = TRUE;
- if (tree_view->priv->top_row)
- {
- gtk_tree_row_reference_free (tree_view->priv->top_row);
- tree_view->priv->top_row = NULL;
- }
- }
-
- /* if we walk backwards at all, then we need to reset our dy. */
- if (update_dy)
- {
- gint dy;
- if (node != NULL)
- {
- dy = _gtk_rbtree_node_find_offset (tree, node) - area_above;
- }
- else
- {
- dy = 0;
- }
-
- gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
- need_redraw = TRUE;
- }
-
if (tree_view->priv->scroll_to_path)
{
gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
}
_gtk_rbtree_set_fixed_height (tree_view->priv->tree,
- tree_view->priv->fixed_height);
+ tree_view->priv->fixed_height, TRUE);
}
/* Our strategy for finding nodes to validate is a little convoluted. We find
*/
static gboolean
-do_validate_rows (GtkTreeView *tree_view)
+do_validate_rows (GtkTreeView *tree_view, gboolean queue_resize)
{
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
if (!tree_view->priv->fixed_height_check)
{
if (fixed_height)
- _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height);
+ _gtk_rbtree_set_fixed_height (tree_view->priv->tree, prev_height, FALSE);
tree_view->priv->fixed_height_check = 1;
}
/* We temporarily guess a size, under the assumption that it will be the
* same when we get our next size_allocate. If we don't do this, we'll be
* in an inconsistent state when we call top_row_to_dy. */
+
gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
gtk_adjustment_changed (tree_view->priv->hadjustment);
gtk_adjustment_changed (tree_view->priv->vadjustment);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- }
- if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
- gtk_tree_view_top_row_to_dy (tree_view);
- else
- gtk_tree_view_dy_to_top_row (tree_view);
+ if (queue_resize)
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
if (path) gtk_tree_path_free (path);
{
gboolean retval;
- retval = do_validate_rows (tree_view);
+ retval = do_validate_rows (tree_view, TRUE);
if (! retval && tree_view->priv->validate_rows_timer)
{
GDK_THREADS_ENTER ();
- retval = do_validate_rows (tree_view);
+ retval = do_validate_rows (tree_view, TRUE);
if (! retval && tree_view->priv->validate_rows_timer)
{
g_source_remove (tree_view->priv->validate_rows_timer);
}
validate_visible_area (tree_view);
tree_view->priv->presize_handler_timer = 0;
+
+ if (tree_view->priv->fixed_height_mode)
+ {
+ GtkRequisition requisition;
+
+ gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
+
+ tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
+ tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
+ gtk_adjustment_changed (tree_view->priv->hadjustment);
+ gtk_adjustment_changed (tree_view->priv->vadjustment);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
return FALSE;
}
GDK_THREADS_ENTER ();
- if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
+ if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
+ else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
gtk_tree_view_top_row_to_dy (tree_view);
else
gtk_tree_view_dy_to_top_row (tree_view);
GtkTreePath *source_row)
{
g_object_set_data_full (G_OBJECT (context),
- "gtk-tree-view-source-row",
+ I_("gtk-tree-view-source-row"),
source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
(GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
}
if (!dest_row)
{
- g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
+ g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
NULL, NULL);
return;
}
dr->empty_view_drop = empty_view_drop;
dr->drop_append_mode = drop_append_mode;
- g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
+ g_object_set_data_full (G_OBJECT (context), I_("gtk-tree-view-dest-row"),
dr, (GDestroyNotify) dest_row_free);
}
GdkDragAction suggested_action)
{
g_object_set_data (G_OBJECT (context),
- "gtk-tree-view-status-pending",
+ I_("gtk-tree-view-status-pending"),
GINT_TO_POINTER (suggested_action));
}
di = g_new0 (TreeViewDragInfo, 1);
g_object_set_data_full (G_OBJECT (tree_view),
- "gtk-tree-view-drag-info",
+ I_("gtk-tree-view-drag-info"),
di,
(GDestroyNotify) destroy_info);
}
static void
remove_info (GtkTreeView *tree_view)
{
- g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
+ g_object_set_data (G_OBJECT (tree_view), I_("gtk-tree-view-drag-info"), NULL);
}
#if 0
path))
goto out;
- /* FIXME Check whether we're a start button, if not return FALSE and
- * free path
- */
+ if (!(GDK_BUTTON1_MASK << (button - 1) & di->start_button_mask))
+ goto out;
/* Now we can begin the drag */
goto done;
/* If drag_data_get does nothing, try providing row data. */
- if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+ if (selection_data->target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
{
gtk_tree_set_row_drag_data (selection_data,
model,
GdkDragContext *context,
guint time)
{
- TreeViewDragInfo *di;
-
- di = get_info (GTK_TREE_VIEW (widget));
-
/* unset any highlight row */
gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
NULL,
{
gboolean empty;
GtkTreePath *path = NULL;
- GtkTreeModel *model;
GtkTreeViewDropPosition pos;
GtkTreeView *tree_view;
GdkDragAction suggested_action = 0;
gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
/* we only know this *after* set_desination_row */
- model = gtk_tree_view_get_model (tree_view);
empty = tree_view->priv->empty_view_drop;
if (path == NULL && !empty)
g_timeout_add (150, scroll_row_timeout, tree_view);
}
- if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
+ if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
{
/* Request data so we can use the source row when
* determining whether to accept the drop
GtkDirectionType dir)
{
GtkWidget *focus_child;
- GtkContainer *container;
GList *last_column, *first_column;
GList *tmp_list;
return FALSE;
focus_child = GTK_CONTAINER (tree_view)->focus_child;
- container = GTK_CONTAINER (tree_view);
first_column = tree_view->priv->columns;
while (first_column)
if (tree_view->priv->hadjustment != hadj)
{
tree_view->priv->hadjustment = hadj;
- g_object_ref (tree_view->priv->hadjustment);
- gtk_object_sink (GTK_OBJECT (tree_view->priv->hadjustment));
+ g_object_ref_sink (tree_view->priv->hadjustment);
g_signal_connect (tree_view->priv->hadjustment, "value_changed",
G_CALLBACK (gtk_tree_view_adjustment_changed),
if (tree_view->priv->vadjustment != vadj)
{
tree_view->priv->vadjustment = vadj;
- g_object_ref (tree_view->priv->vadjustment);
- gtk_object_sink (GTK_OBJECT (tree_view->priv->vadjustment));
+ g_object_ref_sink (tree_view->priv->vadjustment);
g_signal_connect (tree_view->priv->vadjustment, "value_changed",
G_CALLBACK (gtk_tree_view_adjustment_changed),
{
tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
_gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
- }
+ }
done:
if (height > 0)
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ {
+ if (tree)
+ _gtk_rbtree_node_mark_valid (tree, tmpnode);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ }
else
install_presize_handler (tree_view);
if (free_path)
gtk_tree_model_ref_node (tree_view->priv->model, iter);
temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
+ if (tree_view->priv->fixed_height > 0)
+ {
+ if (GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_INVALID))
+ {
+ _gtk_rbtree_node_set_height (tree, temp, tree_view->priv->fixed_height);
+ _gtk_rbtree_node_mark_valid (tree, temp);
+ }
+ }
+
if (is_list)
continue;
GtkRBTree *tree,
GtkRBNode *node)
{
+ gint node_dy, height;
GtkTreePath *path = NULL;
if (!GTK_WIDGET_REALIZED (tree_view))
return;
- path = _gtk_tree_view_find_path (tree_view, tree, node);
+ /* just return if the node is visible, avoiding a costly expose */
+ node_dy = _gtk_rbtree_node_find_offset (tree, node);
+ height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
+ if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)
+ && node_dy >= tree_view->priv->vadjustment->value
+ && node_dy + height <= (tree_view->priv->vadjustment->value
+ + tree_view->priv->vadjustment->page_size))
+ return;
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
if (path)
{
/* We process updates because we want to clear old selected items when we scroll.
/* Add the last one */
if (tree_view->priv->column_drop_func == NULL ||
((left_column != column) &&
- (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
+ (* tree_view->priv->column_drop_func) (tree_view, column, left_column, NULL, tree_view->priv->column_drop_func_data)))
{
reorder = g_new (GtkTreeViewColumnReorder, 1);
reorder->left_column = left_column;
area.width = expander_size + 2;
area.height = MAX (CELL_HEIGHT (node, vertical_separator), (expander_size - vertical_separator));
- if (node == tree_view->priv->button_pressed_node)
+ if (GTK_WIDGET_STATE (tree_view) == GTK_STATE_INSENSITIVE)
+ {
+ state = GTK_STATE_INSENSITIVE;
+ }
+ else if (node == tree_view->priv->button_pressed_node)
{
if (x >= area.x && x <= (area.x + area.width) &&
y >= area.y && y <= (area.y + area.height))
GtkRBNode *cursor_node = NULL;
GtkTreePath *cursor_path = NULL;
gint y;
+ gint window_y;
gint vertical_separator;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
g_return_if_fail (cursor_node != NULL);
y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
- y += count * tree_view->priv->vadjustment->page_size;
- if (count > 0)
- y -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (cursor_node));
- else if (count < 0)
- y += ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (cursor_node));
+ window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
+ y += count * (int)tree_view->priv->vadjustment->page_increment;
y = CLAMP (y, (gint)tree_view->priv->vadjustment->lower, (gint)tree_view->priv->vadjustment->upper - vertical_separator);
if (y >= tree_view->priv->height)
y = tree_view->priv->height - 1;
- _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
+ y -= _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
g_return_if_fail (cursor_path != NULL);
- gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, TRUE);
- gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
gtk_tree_path_free (cursor_path);
+
+ y -= window_y;
+ gtk_tree_view_scroll_to_point (tree_view, -1, y);
}
static void
GtkRBTree *cursor_tree = NULL;
GtkRBNode *cursor_node = NULL;
GtkTreePath *cursor_path = NULL;
+ GdkModifierType state;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
return FALSE;
return FALSE;
}
+ if (gtk_get_current_event_state (&state))
+ {
+ if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ tree_view->priv->ctrl_pressed = TRUE;
+ }
+
if (cursor_tree->parent_node)
{
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
cursor_tree = cursor_tree->parent_tree;
gtk_tree_path_up (cursor_path);
- gtk_tree_row_reference_free (tree_view->priv->cursor);
- tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, cursor_path);
- _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
- cursor_node,
- cursor_tree,
- cursor_path,
- 0,
- FALSE);
+
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE);
}
gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
gtk_tree_path_free (cursor_path);
+ tree_view->priv->ctrl_pressed = FALSE;
+
return TRUE;
}
static gboolean
GDK_THREADS_LEAVE ();
- return TRUE;
+ return FALSE;
}
/* Cut and paste from gtkwindow.c */
g_signal_connect (tree_view->priv->search_window, "button_press_event",
G_CALLBACK (gtk_tree_view_search_button_press_event),
tree_view);
+ g_signal_connect (tree_view->priv->search_window, "scroll_event",
+ G_CALLBACK (gtk_tree_view_search_scroll_event),
+ tree_view);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
if (!tree_view->priv->enable_search && !keybinding)
return FALSE;
- if (GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
+ if (tree_view->priv->search_window != NULL &&
+ GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
return TRUE;
for (list = tree_view->priv->columns; list; list = list->next)
width = MAX (column->min_width,
width);
if (column->max_width != -1)
- width = MIN (width, column->max_width != -1);
+ width = MIN (width, column->max_width);
*x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
if (model == tree_view->priv->model)
return;
+ if (tree_view->priv->scroll_to_path)
+ {
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
+ tree_view->priv->scroll_to_path = NULL;
+ }
+
if (tree_view->priv->model)
{
GList *tmplist = tree_view->priv->columns;
tree_view->priv->model);
if (tree_view->priv->tree)
- {
- _gtk_rbtree_free (tree_view->priv->tree);
- tree_view->priv->tree = NULL;
- }
-
- tree_view->priv->prelight_node = NULL;
- tree_view->priv->prelight_tree = NULL;
- tree_view->priv->button_pressed_node = NULL;
- tree_view->priv->button_pressed_tree = NULL;
+ gtk_tree_view_free_rbtree (tree_view);
gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
tree_view->priv->drag_dest_row = NULL;
tree_view->priv->model = model;
-
if (tree_view->priv->model)
{
gint i;
g_object_notify (G_OBJECT (tree_view), "model");
+ if (tree_view->priv->selection)
+ _gtk_tree_selection_emit_changed (tree_view->priv->selection);
+
if (GTK_WIDGET_REALIZED (tree_view))
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
}
+/**
+ * gtk_tree_view_get_headers_clickable:
+ * @tree_view: A #GtkTreeView.
+ *
+ * Return value: %TRUE if all header columns are clickable, otherwise %FALSE
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_tree_view_get_headers_clickable (GtkTreeView *tree_view)
+{
+ GList *list;
+
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ for (list = tree_view->priv->columns; list; list = list->next)
+ if (!GTK_TREE_VIEW_COLUMN (list->data)->clickable)
+ return FALSE;
+
+ return TRUE;
+}
+
/**
* gtk_tree_view_set_rules_hint
* @tree_view: a #GtkTreeView
g_return_val_if_fail (gtk_tree_view_column_get_sizing (column)
== GTK_TREE_VIEW_COLUMN_FIXED, -1);
- g_object_ref (column);
- gtk_object_sink (GTK_OBJECT (column));
+ g_object_ref_sink (column);
if (tree_view->priv->n_columns == 0 &&
GTK_WIDGET_REALIZED (tree_view) &&
* @tree_view: A #GtkTreeView
* @column: %NULL, or the column to draw the expander arrow at.
*
- * Sets the column to draw the expander arrow at. It must be in @tree_view. If
- * @column is %NULL, then the expander arrow is always at the first visible
- * column.
+ * Sets the column to draw the expander arrow at. It must be in @tree_view.
+ * If @column is %NULL, then the expander arrow is always at the first
+ * visible column.
+ *
+ * If you do not want expander arrow to appear in your tree, set the
+ * expander column to a hidden column.
**/
void
gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
* scrolling code, we short-circuit validate_visible_area's immplementation as
* it is much slower than just going to the point.
*/
- if (! GTK_WIDGET_REALIZED (tree_view) ||
+ if (! GTK_WIDGET_VISIBLE (tree_view) ||
+ ! GTK_WIDGET_REALIZED (tree_view) ||
+ GTK_WIDGET_ALLOC_NEEDED (tree_view) ||
GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
{
if (tree_view->priv->scroll_to_path)
gtk_tree_view_expand_all_emission_helper,
tree_view);
}
-
-static void
-gtk_tree_view_expand_all_helper (GtkRBTree *tree,
- GtkRBNode *node,
- gpointer data)
-{
- GtkTreeView *tree_view = data;
-
- if (node->children)
- _gtk_rbtree_traverse (node->children,
- node->children->root,
- G_PRE_ORDER,
- gtk_tree_view_expand_all_helper,
- data);
- else if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT && node->children == NULL)
- {
- GtkTreePath *path;
- GtkTreeIter iter;
- GtkTreeIter child;
-
- node->children = _gtk_rbtree_new ();
- node->children->parent_tree = tree;
- node->children->parent_node = node;
- path = _gtk_tree_view_find_path (tree_view, tree, node);
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
- gtk_tree_model_iter_children (tree_view->priv->model, &child, &iter);
- gtk_tree_view_build_tree (tree_view,
- node->children,
- &child,
- gtk_tree_path_get_depth (path) + 1,
- TRUE);
-
- g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
- _gtk_rbtree_traverse (node->children,
- node->children->root,
- G_PRE_ORDER,
- gtk_tree_view_expand_all_emission_helper,
- tree_view);
- gtk_tree_path_free (path);
- }
-}
-
/**
* gtk_tree_view_expand_all:
* @tree_view: A #GtkTreeView.
void
gtk_tree_view_expand_all (GtkTreeView *tree_view)
{
+ GtkTreePath *path;
+ GtkRBTree *tree;
+ GtkRBNode *node;
+
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
if (tree_view->priv->tree == NULL)
return;
- _gtk_rbtree_traverse (tree_view->priv->tree,
- tree_view->priv->tree->root,
- G_PRE_ORDER,
- gtk_tree_view_expand_all_helper,
- tree_view);
+ path = gtk_tree_path_new_first ();
+ _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+
+ while (node)
+ {
+ gtk_tree_view_real_expand_row (tree_view, path, tree, node, TRUE, FALSE);
+ node = _gtk_rbtree_next (tree, node);
+ gtk_tree_path_next (path);
+ }
+
+ gtk_tree_path_free (path);
}
/* Timeout to animate the expander during expands and collapses */
GtkTreeIter temp;
gboolean expand;
+ if (animate)
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
+ "gtk-enable-animations", &animate,
+ NULL);
+
remove_auto_expand_timeout (tree_view);
if (node->children && !open_all)
install_presize_handler (tree_view);
g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
+ if (open_all)
+ {
+ _gtk_rbtree_traverse (node->children,
+ node->children->root,
+ G_PRE_ORDER,
+ gtk_tree_view_expand_all_emission_helper,
+ tree_view);
+ }
return TRUE;
}
gboolean collapse;
gint x, y;
GList *list;
- GdkDisplay *display;
GdkWindow *child, *parent;
+ if (animate)
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (tree_view)),
+ "gtk-enable-animations", &animate,
+ NULL);
+
remove_auto_expand_timeout (tree_view);
if (node->children == NULL)
gtk_tree_path_free (lsc);
}
+ if (tree_view->priv->expanded_collapsed_node != NULL)
+ {
+ GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
+ GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
+
+ tree_view->priv->expanded_collapsed_node = NULL;
+ }
+
if (gtk_tree_view_unref_and_check_selection_tree (tree_view, node->children))
{
_gtk_rbtree_remove (node->children);
tree_view->priv->expand_collapse_timeout = 0;
}
- if (tree_view->priv->expanded_collapsed_node != NULL)
- {
- GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
- GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
-
- tree_view->priv->expanded_collapsed_node = NULL;
- }
-
if (animate)
{
tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
/* now that we've collapsed all rows, we want to try to set the prelight
* again. To do this, we fake a motion event and send it to ourselves. */
- display = gdk_drawable_get_display (tree_view->priv->bin_window);
child = tree_view->priv->bin_window;
parent = gdk_window_get_parent (child);
GList *list;
gint remaining_x = x;
gboolean found = FALSE;
+ gboolean rtl;
- for (list = tree_view->priv->columns; list; list = list->next)
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
{
tmp_column = list->data;
*wy = ty - tree_view->priv->dy;
}
+/**
+ * gtk_tree_view_get_visible_range:
+ * @tree_view: A #GtkTreeView
+ * @start_path: Return location for start of region, or %NULL.
+ * @end_path: Return location for end of region, or %NULL.
+ *
+ * Sets @start_path and @end_path to be the first and last visible path.
+ * Note that there may be invisible paths in between.
+ *
+ * The paths should be freed with gtk_tree_path_free() after use.
+ *
+ * Returns: %TRUE, if valid paths were placed in @start_path and @end_path.
+ *
+ * Since: 2.8
+ **/
+gboolean
+gtk_tree_view_get_visible_range (GtkTreeView *tree_view,
+ GtkTreePath **start_path,
+ GtkTreePath **end_path)
+{
+ GtkRBTree *tree;
+ GtkRBNode *node;
+
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ if (!tree_view->priv->tree)
+ return FALSE;
+
+ if (start_path)
+ {
+ _gtk_rbtree_find_offset (tree_view->priv->tree,
+ TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, 0),
+ &tree, &node);
+ *start_path = _gtk_tree_view_find_path (tree_view, tree, node);
+ }
+
+ if (end_path)
+ {
+ gint y;
+
+ if (tree_view->priv->height < tree_view->priv->vadjustment->page_size)
+ y = tree_view->priv->height - 1;
+ else
+ y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, tree_view->priv->vadjustment->page_size) - 1;
+
+ _gtk_rbtree_find_offset (tree_view->priv->tree, y, &tree, &node);
+ *end_path = _gtk_tree_view_find_path (tree_view, tree, node);
+ }
+
+ return TRUE;
+}
+
static void
unset_reorderable (GtkTreeView *tree_view)
{
gtk_drag_source_set (GTK_WIDGET (tree_view),
0,
- NULL,
- 0,
+ targets,
+ n_targets,
actions);
di = ensure_info (tree_view);
gtk_drag_dest_set (GTK_WIDGET (tree_view),
0,
- NULL,
- 0,
+ targets,
+ n_targets,
actions);
di = ensure_info (tree_view);
*
* Determines the destination row for a given position.
*
- * Return value: whether there is a row at the given postiion,
+ * Return value: whether there is a row at the given position.
**/
gboolean
gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
* @tree_view: a #GtkTreeView
* @path: a #GtkTreePath in @tree_view
*
- * Creates a #GdkPixmap representation of the row at @path. This image is used
- * for a drag icon.
+ * Creates a #GdkPixmap representation of the row at @path.
+ * This image is used for a drag icon.
*
* Return value: a newly-allocated pixmap of the drag icon.
**/
gint bin_window_width;
gboolean is_separator = FALSE;
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+ g_return_val_if_fail (path != NULL, NULL);
+
widget = GTK_WIDGET (tree_view);
+ if (!GTK_WIDGET_REALIZED (tree_view))
+ return NULL;
+
depth = gtk_tree_path_get_depth (path);
_gtk_tree_view_find_node (tree_view,
* @enable_search: %TRUE, if the user can search interactively
*
* If @enable_search is set, then the user can type in text to search through
- * the tree interactively.
+ * the tree interactively (this is sometimes called "typeahead find").
+ *
+ * Note that even if this is %FALSE, the user can still initiate a search
+ * using the "start-interactive-search" key binding.
*/
void
gtk_tree_view_set_enable_search (GtkTreeView *tree_view,
* gtk_tree_view_get_enable_search:
* @tree_view: A #GtkTreeView
*
- * Returns whether or not the tree allows interactive searching.
+ * Returns whether or not the tree allows to start interactive searching
+ * by typing in text.
*
* Return value: whether or not to let the user search interactively
*/
/**
* gtk_tree_view_set_search_column:
* @tree_view: A #GtkTreeView
- * @column: the column of the model to search in
+ * @column: the column of the model to search in, or -1 to disable searching
*
* Sets @column as the column where the interactive search code should
- * search in. Additionally, turns on interactive searching. Note that
- * @column refers to a column of the model.
+ * search in.
+ *
+ * If the sort column is set, users can use the "start-interactive-search"
+ * key binding to bring up search popup. The enable-search property controls
+ * whether simply typing text will also start an interactive search.
+ *
+ * Note that @column refers to a column of the model.
*/
void
gtk_tree_view_set_search_column (GtkTreeView *tree_view,
gtk_tree_view_search_dialog_hide (widget, tree_view);
+ if (event->window == tree_view->priv->bin_window)
+ gtk_tree_view_button_press (GTK_WIDGET (tree_view), event);
+
return TRUE;
}
+static gboolean
+gtk_tree_view_search_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event,
+ GtkTreeView *tree_view)
+{
+ gboolean retval = FALSE;
+
+ if (event->direction == GDK_SCROLL_UP)
+ {
+ gtk_tree_view_search_move (widget, tree_view, TRUE);
+ retval = TRUE;
+ }
+ else if (event->direction == GDK_SCROLL_DOWN)
+ {
+ gtk_tree_view_search_move (widget, tree_view, FALSE);
+ retval = TRUE;
+ }
+
+ return retval;
+}
+
static gboolean
gtk_tree_view_search_key_press_event (GtkWidget *widget,
GdkEventKey *event,
/* close window and cancel the search */
if (event->keyval == GDK_Escape ||
- event->keyval == GDK_Tab)
+ event->keyval == GDK_Tab ||
+ event->keyval == GDK_KP_Tab ||
+ event->keyval == GDK_ISO_Left_Tab)
{
gtk_tree_view_search_dialog_hide (widget, tree_view);
return TRUE;
retval = TRUE;
}
+ if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == (GDK_CONTROL_MASK | GDK_SHIFT_MASK))
+ && (event->keyval == GDK_g || event->keyval == GDK_G))
+ {
+ gtk_tree_view_search_move (widget, tree_view, TRUE);
+ retval = TRUE;
+ }
+
/* select next matching iter */
if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
{
retval = TRUE;
}
+ if (((event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
+ && (event->keyval == GDK_g || event->keyval == GDK_G))
+ {
+ gtk_tree_view_search_move (widget, tree_view, FALSE);
+ retval = TRUE;
+ }
+
/* renew the flush timeout */
if (retval && tree_view->priv->typeselect_flush_timeout)
{
gint len;
gint count = 0;
const gchar *text;
- GtkWidget *window;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreeSelection *selection;
g_return_if_fail (GTK_IS_ENTRY (entry));
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- window = gtk_widget_get_parent (entry);
text = gtk_entry_get_text (GTK_ENTRY (entry));
len = strlen (text);
model = gtk_tree_view_get_model (tree_view);
tree_view->priv->pressed_button = -1;
}
+static void
+gtk_tree_view_state_changed (GtkWidget *widget,
+ GtkStateType previous_state)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+ gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+ }
+
+ gtk_widget_queue_draw (widget);
+}
+
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"