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);
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);
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;
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_adjustment_changed (tree_view->priv->vadjustment);
/* now the adjustments and window sizes are in sync, we can sync toprow/dy again */
- 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);
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,
guint flags;
gint highlight_x;
gint bin_window_width;
+ gint bin_window_height;
GtkTreePath *cursor_path;
GtkTreePath *drag_dest_path;
GList *last_column;
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)
continue;
}
+ 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);
+
/* Select the detail for drawing the cell. relevant
* factors are parity, sortedness, and whether to
* display rules.
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
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))
"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_width += 2 * focus_line_width;
- tmp_height += 2 * focus_line_width;
-
+ tmp_height += vertical_separator;
height = MAX (height, tmp_height);
height = MAX (height, tree_view->priv->expander_size);
}
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;
}
_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
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;
}
{
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)
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_set_height (tree, temp, tree_view->priv->fixed_height);
+ _gtk_rbtree_node_mark_valid (tree, temp);
+ }
}
if (is_list)
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.
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
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);
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);
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;
}
*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.
+ *
+ * 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 (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_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,
retval = TRUE;
}
+ if ((event->state & GDK_CONTROL_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)
{