PROP_SEARCH_COLUMN,
PROP_FIXED_HEIGHT_MODE,
PROP_HOVER_SELECTION,
- PROP_HOVER_EXPAND
+ PROP_HOVER_EXPAND,
+ PROP_SHOW_EXPANDERS,
+ PROP_LEVEL_INDENTATION,
+ PROP_RUBBER_BANDING,
+ PROP_ENABLE_GRID_LINES,
+ PROP_ENABLE_TREE_LINES
};
-static void gtk_tree_view_class_init (GtkTreeViewClass *klass);
-static void gtk_tree_view_init (GtkTreeView *tree_view);
-
/* object signals */
static void gtk_tree_view_finalize (GObject *object);
static void gtk_tree_view_set_property (GObject *object,
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 void gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
guint keyval,
guint modmask,
+ gboolean add_shifted_binding,
GtkMovementStep step,
gint count);
static gint gtk_tree_view_unref_and_check_selection_tree (GtkTreeView *tree_view,
gpointer data);
static gboolean expand_collapse_timeout (gpointer data);
static gboolean do_expand_collapse (GtkTreeView *tree_view);
+static void gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view);
/* interactive search */
static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
static void gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
GtkTreeView *tree_view);
static void gtk_tree_view_search_position_func (GtkTreeView *tree_view,
- GtkWidget *search_dialog);
+ GtkWidget *search_dialog,
+ gpointer user_data);
static void gtk_tree_view_search_disable_popdown (GtkEntry *entry,
GtkMenu *menu,
gpointer data);
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);
gint *tx,
gint *ty);
+static gint scroll_row_timeout (gpointer data);
+static void remove_scroll_timeout (GtkTreeView *tree_view);
-static GtkContainerClass *parent_class = NULL;
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
\f
/* GType Methods
*/
-GType
-gtk_tree_view_get_type (void)
-{
- static GType tree_view_type = 0;
-
- if (!tree_view_type)
- {
- static const GTypeInfo tree_view_info =
- {
- sizeof (GtkTreeViewClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_tree_view_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkTreeView),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_tree_view_init
- };
-
- tree_view_type =
- g_type_register_static (GTK_TYPE_CONTAINER, "GtkTreeView",
- &tree_view_info, 0);
- }
-
- return tree_view_type;
-}
+G_DEFINE_TYPE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER)
static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
GtkContainerClass *container_class;
GtkBindingSet *binding_set;
- parent_class = g_type_class_peek_parent (class);
binding_set = gtk_binding_set_by_class (class);
o_class = (GObjectClass *) class;
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;
FALSE,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (o_class,
+ PROP_SHOW_EXPANDERS,
+ g_param_spec_boolean ("show-expanders",
+ P_("Show Expanders"),
+ P_("View has expanders"),
+ TRUE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (o_class,
+ PROP_LEVEL_INDENTATION,
+ g_param_spec_int ("level-indentation",
+ P_("Level Indentation"),
+ P_("Extra indentation for each level"),
+ 0,
+ G_MAXINT,
+ 0,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (o_class,
+ PROP_RUBBER_BANDING,
+ g_param_spec_boolean ("rubber-banding",
+ P_("Rubber Banding"),
+ P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (o_class,
+ PROP_ENABLE_GRID_LINES,
+ g_param_spec_boolean ("enable-grid-lines",
+ P_("Enable Grid Lines"),
+ P_("Whether grid lines should be drawn in the tree view"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
+ g_object_class_install_property (o_class,
+ PROP_ENABLE_TREE_LINES,
+ g_param_spec_boolean ("enable-tree-lines",
+ P_("Enable Tree Lines"),
+ P_("Whether tree lines should be drawn in the tree view"),
+ FALSE,
+ GTK_PARAM_READWRITE));
+
/* Style properties */
#define _TREE_VIEW_EXPANDER_SIZE 12
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
GDK_TYPE_COLOR,
GTK_PARAM_READABLE));
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boolean ("row-ending-details",
+ P_("Row Ending details"),
+ P_("Enable extended row background theming"),
+ FALSE,
+ GTK_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("grid-line-width",
+ P_("Grid line width"),
+ P_("Width, in pixels, of the tree view grid lines"),
+ 0, G_MAXINT, 1,
+ GTK_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_int ("tree-line-width",
+ P_("Tree line width"),
+ P_("Width, in pixels, of the tree view lines"),
+ 0, G_MAXINT, 1,
+ GTK_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_string ("grid-line-pattern",
+ P_("Grid line pattern"),
+ P_("Dash pattern used to draw the tree view grid lines"),
+ "\1\1",
+ GTK_PARAM_READABLE));
+
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_string ("tree-line-pattern",
+ P_("Tree line pattern"),
+ P_("Dash pattern used to draw the tree view lines"),
+ "\1\1",
+ GTK_PARAM_READABLE));
+
/* 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_PATH,
GTK_TYPE_TREE_VIEW_COLUMN);
+ /**
+ * GtkTreeView::test-expand-row:
+ * @tree_view: the object on which the signal is emitted
+ * @iter: the tree iter of the row to expand
+ * @path: a tree path that points to the row
+ *
+ * The given row is about to be expanded (show its children nodes). Use this
+ * signal if you need to control the expandability of individual rows.
+ *
+ * Returns: %TRUE to allow expansion, %FALSE to reject
+ */
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_ITER,
GTK_TYPE_TREE_PATH);
+ /**
+ * GtkTreeView::test-collapse-row:
+ * @tree_view: the object on which the signal is emitted
+ * @iter: the tree iter of the row to collapse
+ * @path: a tree path that points to the row
+ *
+ * The given row is about to be collapsed (hide its children nodes). Use this
+ * signal if you need to control the collapsibility of individual rows.
+ *
+ * Returns: %TRUE to allow expansion, %FALSE to reject
+ */
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_ITER,
GTK_TYPE_TREE_PATH);
+ /**
+ * GtkTreeView::row-expanded:
+ * @tree_view: the object on which the signal is emitted
+ * @iter: the tree iter of the expanded row
+ * @path: a tree path that points to the row
+ *
+ * The given row has been expanded (child nodes are shown).
+ */
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_ITER,
GTK_TYPE_TREE_PATH);
+ /**
+ * GtkTreeView::row-collapsed:
+ * @tree_view: the object on which the signal is emitted
+ * @iter: the tree iter of the collapsed row
+ * @path: a tree path that points to the row
+ *
+ * The given row has been collapsed (child nodes are hidden).
+ */
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_ITER,
GTK_TYPE_TREE_PATH);
+ /**
+ * GtkTreeView::columns-changed:
+ * @tree_view: the object on which the signal is emitted
+ *
+ * The number of columns of the treeview has changed.
+ */
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),
_gtk_marshal_NONE__NONE,
G_TYPE_NONE, 0);
+ /**
+ * GtkTreeView::cursor-changed:
+ * @tree_view: the object on which the signal is emitted
+ *
+ * The position of the cursor (focused cell) has changed.
+ */
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, 0);
/* Key bindings */
- gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0, TRUE,
GTK_MOVEMENT_DISPLAY_LINES, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0, TRUE,
GTK_MOVEMENT_DISPLAY_LINES, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0, TRUE,
GTK_MOVEMENT_DISPLAY_LINES, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0, TRUE,
GTK_MOVEMENT_DISPLAY_LINES, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
+ gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK, FALSE,
GTK_MOVEMENT_DISPLAY_LINES, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK,
+ gtk_tree_view_add_move_binding (binding_set, GDK_n, GDK_CONTROL_MASK, FALSE,
GTK_MOVEMENT_DISPLAY_LINES, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0, TRUE,
GTK_MOVEMENT_BUFFER_ENDS, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0, TRUE,
GTK_MOVEMENT_BUFFER_ENDS, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_End, 0, TRUE,
GTK_MOVEMENT_BUFFER_ENDS, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0, TRUE,
GTK_MOVEMENT_BUFFER_ENDS, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0, TRUE,
GTK_MOVEMENT_PAGES, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0, TRUE,
GTK_MOVEMENT_PAGES, -1);
- gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0, TRUE,
GTK_MOVEMENT_PAGES, 1);
- gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0, TRUE,
GTK_MOVEMENT_PAGES, 1);
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);
tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
tree_view->priv->enable_search = TRUE;
tree_view->priv->search_column = -1;
- tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
+ tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
+ tree_view->priv->search_custom_entry_set = FALSE;
tree_view->priv->typeselect_flush_timeout = 0;
tree_view->priv->init_hadjust_value = TRUE;
tree_view->priv->width = 0;
tree_view->priv->hover_selection = FALSE;
tree_view->priv->hover_expand = FALSE;
+
+ tree_view->priv->level_indentation = 0;
+
+ tree_view->priv->rubber_banding_enable = FALSE;
+
+ tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
+ tree_view->priv->tree_lines_enabled = FALSE;
}
\f
case PROP_HOVER_EXPAND:
tree_view->priv->hover_expand = g_value_get_boolean (value);
break;
+ case PROP_SHOW_EXPANDERS:
+ if (g_value_get_boolean (value))
+ GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+ else
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+ break;
+ case PROP_LEVEL_INDENTATION:
+ tree_view->priv->level_indentation = g_value_get_int (value);
+ break;
+ case PROP_RUBBER_BANDING:
+ tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
+ break;
+ case PROP_ENABLE_GRID_LINES:
+ gtk_tree_view_set_grid_lines (tree_view, g_value_get_boolean (value));
+ break;
+ case PROP_ENABLE_TREE_LINES:
+ gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
+ break;
default:
break;
}
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;
case PROP_HOVER_EXPAND:
g_value_set_boolean (value, tree_view->priv->hover_expand);
break;
+ case PROP_SHOW_EXPANDERS:
+ g_value_set_boolean (value, GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS));
+ break;
+ case PROP_LEVEL_INDENTATION:
+ g_value_set_int (value, tree_view->priv->level_indentation);
+ break;
+ case PROP_RUBBER_BANDING:
+ g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
+ break;
+ case PROP_ENABLE_GRID_LINES:
+ g_value_set_boolean (value, tree_view->priv->grid_lines);
+ break;
+ case PROP_ENABLE_TREE_LINES:
+ g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
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);
+ (* G_OBJECT_CLASS (gtk_tree_view_parent_class)->finalize) (object);
}
\f
/* 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->search_position_destroy && tree_view->priv->search_position_user_data)
+ {
+ (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
+ tree_view->priv->search_position_user_data = NULL;
+ }
+
+ 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;
tree_view->priv->vadjustment = NULL;
}
- if (GTK_OBJECT_CLASS (parent_class)->destroy)
- (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+ if (GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (gtk_tree_view_parent_class)->destroy) (object);
}
\f
{
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]);
+ gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
gtk_style_set_background (widget->style, tree_view->priv->header_window, GTK_STATE_NORMAL);
for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
_gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
+ /* Need to call those here, since they craete GCs */
+ gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+ gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
+
install_presize_handler (tree_view);
}
}
/* GtkWidget::unrealize destroys children and widget->window */
- if (GTK_WIDGET_CLASS (parent_class)->unrealize)
- (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
+ if (GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize)
+ (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->unrealize) (widget);
}
/* GtkWidget::size_request helper */
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));
}
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 (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment),
+ tree_view->priv->height - tree_view->priv->vadjustment->page_size);
+ 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);
gint column_handled_click = FALSE;
gboolean row_double_click = FALSE;
gboolean rtl;
+ gboolean node_selected;
/* Empty tree? */
if (tree_view->priv->tree == NULL)
/* are we in an arrow? */
if (tree_view->priv->prelight_node &&
- GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
+ GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT) &&
+ TREE_VIEW_DRAW_EXPANDERS (tree_view))
{
if (event->button == 1)
{
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;
cell_area.x += horizontal_separator/2;
cell_area.y += vertical_separator/2;
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS(tree_view))
+ if (gtk_tree_view_is_expander_column (tree_view, column))
{
- cell_area.x += depth * tree_view->priv->expander_size;
- cell_area.width -= depth * tree_view->priv->expander_size;
+ if (!rtl)
+ cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+ cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+ if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ {
+ if (!rtl)
+ cell_area.x += depth * tree_view->priv->expander_size;
+ cell_area.width -= depth * tree_view->priv->expander_size;
+ }
}
break;
}
}
/* select */
+ node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
pre_val = tree_view->priv->vadjustment->value;
/* we only handle selection modifications on the first button press
tree_view->priv->pressed_button = event->button;
tree_view->priv->press_start_x = event->x;
tree_view->priv->press_start_y = event->y;
+
+ if (tree_view->priv->rubber_banding_enable
+ && !node_selected
+ && tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ {
+ tree_view->priv->press_start_y += tree_view->priv->dy;
+ tree_view->priv->rubber_band_x = event->x;
+ tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
+ tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
+
+ if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ tree_view->priv->rubber_band_ctrl = TRUE;
+ if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+ tree_view->priv->rubber_band_shift = TRUE;
+ }
}
/* Test if a double click happened on the same row. */
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
return gtk_tree_view_button_release_drag_column (widget, event);
+ if (tree_view->priv->rubber_band_status)
+ gtk_tree_view_stop_rubber_band (tree_view);
+
if (tree_view->priv->pressed_button == event->button)
tree_view->priv->pressed_button = -1;
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,
GtkTreeView *tree_view;
tree_view = GTK_TREE_VIEW (widget);
- tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+ tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window);
return FALSE;
}
/* We are still on the same node,
but we might need to take care of the arrow */
- if (tree && node)
+ if (tree && node && TREE_VIEW_DRAW_EXPANDERS (tree_view))
{
gboolean over_arrow;
gboolean flag_set;
GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node,
GTK_RBNODE_IS_PRELIT);
- if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT)
+ && TREE_VIEW_DRAW_EXPANDERS (tree_view))
{
GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
/* Prelight the new node and arrow */
- if (coords_are_over_arrow (tree_view, tree, node, x, y))
+ if (TREE_VIEW_DRAW_EXPANDERS (tree_view)
+ && coords_are_over_arrow (tree_view, tree, node, x, y))
{
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
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;
return TRUE;
}
+static void
+gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
+{
+ remove_scroll_timeout (tree_view);
+ gtk_grab_remove (GTK_WIDGET (tree_view));
+
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+
+ if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+ {
+ GtkTreePath *tmp_path;
+
+ /* The anchor path should be set to the start path */
+ tmp_path = _gtk_tree_view_find_path (tree_view,
+ tree_view->priv->rubber_band_start_tree,
+ tree_view->priv->rubber_band_start_node);
+
+ if (tree_view->priv->anchor)
+ gtk_tree_row_reference_free (tree_view->priv->anchor);
+
+ tree_view->priv->anchor =
+ gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
+ tree_view->priv->model,
+ tmp_path);
+
+ gtk_tree_path_free (tmp_path);
+
+ /* ... and the cursor to the end path */
+ tmp_path = _gtk_tree_view_find_path (tree_view,
+ tree_view->priv->rubber_band_end_tree,
+ tree_view->priv->rubber_band_end_node);
+ gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
+ gtk_tree_path_free (tmp_path);
+
+ _gtk_tree_selection_emit_changed (tree_view->priv->selection);
+ }
+
+ /* Clear status variables */
+ tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
+ tree_view->priv->rubber_band_shift = 0;
+ tree_view->priv->rubber_band_ctrl = 0;
+
+ tree_view->priv->rubber_band_start_node = NULL;
+ tree_view->priv->rubber_band_start_tree = NULL;
+ tree_view->priv->rubber_band_end_node = NULL;
+ tree_view->priv->rubber_band_end_tree = NULL;
+}
+
+static void
+gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
+ GtkRBTree *start_tree,
+ GtkRBNode *start_node,
+ GtkRBTree *end_tree,
+ GtkRBNode *end_node,
+ gboolean select,
+ gboolean skip_start,
+ gboolean skip_end)
+{
+ if (start_node == end_node)
+ return;
+
+ /* We skip the first node and jump inside the loop */
+ if (skip_start)
+ goto skip_first;
+
+ do
+ {
+ if (select)
+ {
+ if (tree_view->priv->rubber_band_shift)
+ GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ else if (tree_view->priv->rubber_band_ctrl)
+ {
+ /* Toggle the selection state */
+ if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+ GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ else
+ GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ }
+ else
+ GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ }
+ else
+ {
+ /* Mirror the above */
+ if (tree_view->priv->rubber_band_shift)
+ GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ else if (tree_view->priv->rubber_band_ctrl)
+ {
+ /* Toggle the selection state */
+ if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
+ GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ else
+ GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ }
+ else
+ GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
+ }
+
+ _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
+
+ if (start_node == end_node)
+ break;
+
+skip_first:
+
+ if (start_node->children)
+ {
+ start_tree = start_node->children;
+ start_node = start_tree->root;
+ while (start_node->left != start_tree->nil)
+ start_node = start_node->left;
+ }
+ else
+ {
+ _gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
+
+ if (!start_tree)
+ /* Ran out of tree */
+ break;
+ }
+
+ if (skip_end && start_node == end_node)
+ break;
+ }
+ while (TRUE);
+}
+
+static void
+gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
+{
+ GtkRBTree *start_tree, *end_tree;
+ GtkRBNode *start_node, *end_node;
+
+ _gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
+ _gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
+
+ /* Handle the start area first */
+ if (!tree_view->priv->rubber_band_start_node)
+ {
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ start_tree,
+ start_node,
+ end_tree,
+ end_node,
+ TRUE,
+ FALSE,
+ FALSE);
+ }
+ else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
+ _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
+ {
+ /* New node is above the old one; selection became bigger */
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ start_tree,
+ start_node,
+ tree_view->priv->rubber_band_start_tree,
+ tree_view->priv->rubber_band_start_node,
+ TRUE,
+ FALSE,
+ TRUE);
+ }
+ else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
+ _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
+ {
+ /* New node is below the old one; selection became smaller */
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ tree_view->priv->rubber_band_start_tree,
+ tree_view->priv->rubber_band_start_node,
+ start_tree,
+ start_node,
+ FALSE,
+ FALSE,
+ TRUE);
+ }
+
+ tree_view->priv->rubber_band_start_tree = start_tree;
+ tree_view->priv->rubber_band_start_node = start_node;
+
+ /* Next, handle the end area */
+ if (!tree_view->priv->rubber_band_end_node)
+ {
+ /* In the event this happens, start_node was also NULL; this case is
+ * handled above.
+ */
+ }
+ else if (!end_node)
+ {
+ /* Find the last node in the tree */
+ _gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
+ &end_tree, &end_node);
+
+ /* Selection reached end of the tree */
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ tree_view->priv->rubber_band_end_tree,
+ tree_view->priv->rubber_band_end_node,
+ end_tree,
+ end_node,
+ TRUE,
+ TRUE,
+ FALSE);
+ }
+ else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
+ _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
+ {
+ /* New node is below the old one; selection became bigger */
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ tree_view->priv->rubber_band_end_tree,
+ tree_view->priv->rubber_band_end_node,
+ end_tree,
+ end_node,
+ TRUE,
+ TRUE,
+ FALSE);
+ }
+ else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
+ _gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
+ {
+ /* New node is above the old one; selection became smaller */
+ gtk_tree_view_update_rubber_band_selection_range (tree_view,
+ end_tree,
+ end_node,
+ tree_view->priv->rubber_band_end_tree,
+ tree_view->priv->rubber_band_end_node,
+ FALSE,
+ TRUE,
+ FALSE);
+ }
+
+ tree_view->priv->rubber_band_end_tree = end_tree;
+ tree_view->priv->rubber_band_end_node = end_node;
+}
+
+static void
+gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
+{
+ gint x, y;
+ GdkRectangle old_area;
+ GdkRectangle new_area;
+ GdkRectangle common;
+ GdkRegion *invalid_region;
+
+ old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
+ old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
+ old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
+ old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
+
+ gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
+
+ x = MAX (x, 0);
+ y = MAX (y, 0) + tree_view->priv->dy;
+
+ new_area.x = MIN (tree_view->priv->press_start_x, x);
+ new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
+ new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
+ new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
+
+ invalid_region = gdk_region_rectangle (&old_area);
+ gdk_region_union_with_rect (invalid_region, &new_area);
+
+ gdk_rectangle_intersect (&old_area, &new_area, &common);
+ if (common.width > 2 && common.height > 2)
+ {
+ GdkRegion *common_region;
+
+ /* make sure the border is invalidated */
+ common.x += 1;
+ common.y += 1;
+ common.width -= 2;
+ common.height -= 2;
+
+ common_region = gdk_region_rectangle (&common);
+
+ gdk_region_subtract (invalid_region, common_region);
+ gdk_region_destroy (common_region);
+ }
+
+ gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
+
+ gdk_region_destroy (invalid_region);
+
+ tree_view->priv->rubber_band_x = x;
+ tree_view->priv->rubber_band_y = y;
+
+ gtk_tree_view_update_rubber_band_selection (tree_view);
+}
+
+static void
+gtk_tree_view_paint_rubber_band (GtkTreeView *tree_view,
+ GdkRectangle *area)
+{
+ cairo_t *cr;
+ GdkRectangle rect;
+ GdkRectangle rubber_rect;
+
+ rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
+ rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
+ rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
+ rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
+
+ if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
+ return;
+
+ cr = gdk_cairo_create (tree_view->priv->bin_window);
+ cairo_set_line_width (cr, 1.0);
+
+ cairo_set_source_rgba (cr,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
+ .25);
+
+ gdk_cairo_rectangle (cr, &rect);
+ cairo_clip (cr);
+ cairo_paint (cr);
+
+ cairo_set_source_rgb (cr,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
+ GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
+
+ cairo_rectangle (cr,
+ rubber_rect.x + 0.5, rubber_rect.y + 0.5,
+ rubber_rect.width - 1, rubber_rect.height - 1);
+ cairo_stroke (cr);
+
+ cairo_destroy (cr);
+}
+
static gboolean
gtk_tree_view_motion_bin_window (GtkWidget *widget,
GdkEventMotion *event)
if (tree_view->priv->tree == NULL)
return FALSE;
+ if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
+ {
+ gtk_grab_add (GTK_WIDGET (tree_view));
+ gtk_tree_view_update_rubber_band (tree_view);
+
+ tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
+ }
+ else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+ {
+ gtk_tree_view_update_rubber_band (tree_view);
+
+ if (tree_view->priv->scroll_timeout == 0)
+ {
+ tree_view->priv->scroll_timeout = g_timeout_add (150, scroll_row_timeout, tree_view);
+ }
+ }
+
/* only check for an initiated drag when a button is pressed */
- if (tree_view->priv->pressed_button >= 0)
+ if (tree_view->priv->pressed_button >= 0
+ && !tree_view->priv->rubber_band_status)
gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
1, 1, w, h);
}
+static void
+gtk_tree_view_draw_grid_lines (GtkTreeView *tree_view,
+ GdkEventExpose *event,
+ gint n_visible_columns)
+{
+ GList *list = tree_view->priv->columns;
+ gint i = 0;
+ gint current_x = 0;
+
+ if (tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_VERTICAL
+ && tree_view->priv->grid_lines != GTK_TREE_VIEW_GRID_LINES_BOTH)
+ return;
+
+ /* Only draw the lines for visible rows and columns */
+ for (list = tree_view->priv->columns; list; list = list->next, i++)
+ {
+ GtkTreeViewColumn *column = list->data;
+
+ /* We don't want a line for the list column */
+ if (i == n_visible_columns - 1)
+ break;
+
+ if (! column->visible)
+ continue;
+
+ current_x += column->width;
+
+ gdk_draw_line (event->window,
+ tree_view->priv->grid_line_gc,
+ current_x - 1, 0,
+ current_x - 1, tree_view->priv->height);
+ }
+}
+
/* Warning: Very scary function.
* Modify at your own risk
*
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;
GdkRectangle cell_area;
guint flags;
gint highlight_x;
+ gint expander_cell_width;
gint bin_window_width;
+ gint bin_window_height;
GtkTreePath *cursor_path;
GtkTreePath *drag_dest_path;
GList *last_column;
gint n_visible_columns;
gint pointer_x, pointer_y;
gboolean got_pointer = FALSE;
+ gboolean row_ending_details;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
"vertical-separator", &vertical_separator,
"allow-rules", &allow_rules,
"focus-line-width", &focus_line_width,
+ "row-ending-details", &row_ending_details,
NULL);
if (tree_view->priv->tree == NULL)
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)
{
gboolean parity;
gboolean is_separator = FALSE;
+ gboolean is_first = FALSE;
+ gboolean is_last = FALSE;
if (tree_view->priv->row_separator_func)
{
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 */
+ expander_cell_width = 0;
background_area.y = y_offset + event->area.y;
background_area.height = max_height;
parity = _gtk_rbtree_node_find_parity (tree, node);
- has_special_cell = gtk_tree_view_has_special_cell (tree_view);
-
+ /* 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));
+ list;
+ list = (rtl ? list->prev : list->next))
+ {
GtkTreeViewColumn *column = list->data;
const gchar *detail = NULL;
GtkStateType state;
state = GTK_STATE_NORMAL;
/* Draw background */
- gtk_paint_flat_box (widget->style,
- event->window,
- state,
- GTK_SHADOW_NONE,
- &event->area,
- widget,
- detail,
- background_area.x,
- background_area.y,
- background_area.width,
- background_area.height);
+ if (row_ending_details)
+ {
+ char new_detail[128];
+
+ is_first = (rtl ? !list->next : !list->prev);
+ is_last = (rtl ? !list->prev : !list->next);
+
+ /* (I don't like the snprintfs either, but couldn't find a
+ * less messy way).
+ */
+ if (is_first && is_last)
+ snprintf (new_detail, 127, "%s", detail);
+ else if (is_first)
+ snprintf (new_detail, 127, "%s_start", detail);
+ else if (is_last)
+ snprintf (new_detail, 127, "%s_end", detail);
+ else
+ snprintf (new_detail, 128, "%s_middle", detail);
+
+ gtk_paint_flat_box (widget->style,
+ event->window,
+ state,
+ GTK_SHADOW_NONE,
+ &event->area,
+ widget,
+ new_detail,
+ background_area.x,
+ background_area.y,
+ background_area.width,
+ background_area.height);
+ }
+ else
+ {
+ gtk_paint_flat_box (widget->style,
+ event->window,
+ state,
+ GTK_SHADOW_NONE,
+ &event->area,
+ widget,
+ detail,
+ background_area.x,
+ background_area.y,
+ background_area.width,
+ background_area.height);
+ }
+
+ if (tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_HORIZONTAL
+ || tree_view->priv->grid_lines == GTK_TREE_VIEW_GRID_LINES_BOTH)
+ {
+ if (background_area.y > 0)
+ gdk_draw_line (event->window,
+ tree_view->priv->grid_line_gc,
+ background_area.x, background_area.y,
+ background_area.x + background_area.width,
+ background_area.y);
+ }
if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS(tree_view))
+ tree_view->priv->tree_lines_enabled)
+ {
+ if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT
+ && depth > 1)
+ {
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y + background_area.height / 2,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.1),
+ background_area.y + background_area.height / 2);
+ }
+ else if (depth > 1)
+ {
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y + background_area.height / 2,
+ background_area.x + tree_view->priv->expander_size * (depth - 0.5),
+ background_area.y + background_area.height / 2);
+ }
+
+ if (depth > 1)
+ {
+ gint i;
+ GtkRBNode *tmp_node;
+ GtkRBTree *tmp_tree;
+
+ if (!_gtk_rbtree_next (tree, node))
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y + background_area.height / 2);
+ else
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y,
+ background_area.x + tree_view->priv->expander_size * (depth - 1.5),
+ background_area.y + background_area.height);
+
+ tmp_node = tree->parent_node;
+ tmp_tree = tree->parent_tree;
+
+ for (i = depth - 2; i > 0; i--)
+ {
+ if (_gtk_rbtree_next (tmp_tree, tmp_node))
+ gdk_draw_line (event->window,
+ tree_view->priv->tree_line_gc,
+ background_area.x + tree_view->priv->expander_size * (i - 0.5),
+ background_area.y,
+ background_area.x + tree_view->priv->expander_size * (i - 0.5),
+ background_area.y + background_area.height);
+
+ tmp_node = tmp_tree->parent_node;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+ }
+ }
+
+ if (gtk_tree_view_is_expander_column (tree_view, column))
{
if (!rtl)
- cell_area.x += depth * tree_view->priv->expander_size;
- cell_area.width -= depth * tree_view->priv->expander_size;
+ cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+ cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+ if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
+ {
+ if (!rtl)
+ cell_area.x += depth * tree_view->priv->expander_size;
+ cell_area.width -= depth * tree_view->priv->expander_size;
+ }
/* If we have an expander column, the highlight underline
* starts with that column, so that it indicates which
* level of the tree we're dropping at.
*/
highlight_x = cell_area.x;
+ expander_cell_width = cell_area.width;
+
if (is_separator)
gtk_paint_hline (widget->style,
event->window,
&cell_area,
&event->area,
flags);
- if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
+ if (TREE_VIEW_DRAW_EXPANDERS(tree_view)
+ && (node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT)
{
if (!got_pointer)
{
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),
- NULL,
- widget,
- "treeview-drop-indicator",
- 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
- - focus_line_width / 2,
- width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+
+ if (row_ending_details)
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ GTK_WIDGET_STATE (widget),
+ NULL,
+ widget,
+ (is_first
+ ? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
+ : (is_last ? "treeview-drop-indicator-right" : "tree-view-drop-indicator-middle" )),
+ 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+ - focus_line_width / 2,
+ width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
- focus_line_width + 1);
+ else
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ GTK_WIDGET_STATE (widget),
+ NULL,
+ widget,
+ "treeview-drop-indicator",
+ 0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
+ - focus_line_width / 2,
+ width, ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node))
+ - focus_line_width + 1);
break;
}
if (highlight_y >= 0)
{
gdk_draw_line (event->window,
- widget->style->black_gc,
- highlight_x,
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+ rtl ? highlight_x + expander_cell_width : highlight_x,
highlight_y,
- bin_window_width - highlight_x,
+ rtl ? 0 : bin_window_width,
highlight_y);
}
}
gdk_drawable_get_size (tree_view->priv->bin_window,
&width, NULL);
- gtk_paint_focus (widget->style,
- tree_view->priv->bin_window,
- focus_rect_state,
- NULL,
- widget,
- "treeview",
- 0,
- BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
- width,
- ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)));
+
+ if (row_ending_details)
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ focus_rect_state,
+ NULL,
+ widget,
+ (is_first
+ ? (is_last ? "treeview" : "treeview-left" )
+ : (is_last ? "treeview-right" : "treeview-middle" )),
+ 0,
+ BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
+ width,
+ ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)));
+ else
+ gtk_paint_focus (widget->style,
+ tree_view->priv->bin_window,
+ focus_rect_state,
+ NULL,
+ widget,
+ "treeview",
+ 0,
+ BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
+ width,
+ ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)));
}
y_offset += max_height;
else
{
gboolean done = FALSE;
+
do
{
node = _gtk_rbtree_next (tree, node);
}
while (y_offset < event->area.height);
- done:
+done:
+ gtk_tree_view_draw_grid_lines (tree_view, event, n_visible_columns);
+
+ if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+ {
+ GdkRectangle *rectangles;
+ gint n_rectangles;
+
+ gdk_region_get_rectangles (event->region,
+ &rectangles,
+ &n_rectangles);
+
+ while (n_rectangles--)
+ gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
+
+ g_free (rectangles);
+ }
+
if (cursor_path)
gtk_tree_path_free (cursor_path);
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
}
/* Chain up to the parent class. It handles the keybindings. */
- if ((* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event))
+ if ((* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_press_event) (widget, event))
return TRUE;
/* We pass the event to the search_entry. If its text changes, then we start
* the typeahead find capabilities. */
- if (tree_view->priv->enable_search)
+ if (tree_view->priv->enable_search
+ && !tree_view->priv->search_custom_entry_set)
{
GdkEvent *new_event;
char *old_text;
/* 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,
gtk_tree_view_key_release (GtkWidget *widget,
GdkEventKey *event)
{
- return (* GTK_WIDGET_CLASS (parent_class)->key_release_event) (widget, event);
+ return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
}
/* FIXME Is this function necessary? Can I get an enter_notify event
{
GtkTreeView *tree_view;
- tree_view = GTK_TREE_VIEW (widget);
- tree_view->priv->pressed_button = -1;
-
if (event->mode == GDK_CROSSING_GRAB)
return TRUE;
+ tree_view = GTK_TREE_VIEW (widget);
+
if (tree_view->priv->prelight_node)
_gtk_tree_view_queue_draw_node (tree_view,
tree_view->priv->prelight_tree,
GTK_RBNODE_GET_HEIGHT (node));
}
+static gboolean
+node_is_visible (GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ int y;
+ int height;
+
+ y = _gtk_rbtree_node_find_offset (tree, node);
+ height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
+
+ if (y >= tree_view->priv->vadjustment->value &&
+ y + height <= (tree_view->priv->vadjustment->value
+ + tree_view->priv->vadjustment->page_size))
+ return TRUE;
+
+ return FALSE;
+}
+
/* Returns TRUE if it updated the size
*/
static gboolean
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);
}
else
height = 2 + 2 * focus_pad;
- if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ if (gtk_tree_view_is_expander_column (tree_view, column))
{
- tmp_width = tmp_width + horizontal_separator + depth * (tree_view->priv->expander_size);
+ tmp_width = tmp_width + horizontal_separator + (depth - 1) * tree_view->priv->level_indentation;
+
+ if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ tmp_width += depth * tree_view->priv->expander_size;
}
else
tmp_width = tmp_width + horizontal_separator;
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
- need_redraw = TRUE;
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
if (validate_row (tree_view, tree, node, &iter, path))
size_changed = TRUE;
}
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;
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
- need_redraw = TRUE;
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
if (validate_row (tree_view, tree, node, &iter, path))
size_changed = TRUE;
}
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
- need_redraw = TRUE;
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
if (validate_row (tree_view, tree, node, &iter, path))
size_changed = TRUE;
}
{
gint old_height = new_height;
- need_redraw = TRUE;
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
if (validate_row (tree_view, tree, node, &iter, path))
{
new_height = GTK_RBNODE_GET_HEIGHT (node);
{
gint old_height = new_height;
- need_redraw = TRUE;
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
if (validate_row (tree_view, tree, node, &iter, above_path))
{
new_height = GTK_RBNODE_GET_HEIGHT (node);
gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
gtk_tree_view_dy_to_top_row (tree_view);
}
+ else if (tree_view->priv->vadjustment->value + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+ {
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), tree_view->priv->height - tree_view->priv->vadjustment->page_size);
+ gtk_tree_view_dy_to_top_row (tree_view);
+ }
else
gtk_tree_view_top_row_to_dy (tree_view);
}
_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;
}
gtk_adjustment_changed (tree_view->priv->vadjustment);
if (queue_resize)
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
}
if (path) gtk_tree_path_free (path);
if (tree_view->priv->fixed_height_mode)
{
GtkRequisition requisition;
- gint height_old = tree_view->priv->height;
gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
tree_view->priv->dy = _gtk_rbtree_node_find_offset (tree, node);
tree_view->priv->dy += tree_view->priv->top_row_dy;
+
+ if (tree_view->priv->dy + tree_view->priv->vadjustment->page_size > tree_view->priv->height)
+ tree_view->priv->dy = tree_view->priv->height - tree_view->priv->vadjustment->page_size;
+
gtk_adjustment_set_value (tree_view->priv->vadjustment,
(gdouble)tree_view->priv->dy);
}
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
tree_view->priv->scroll_timeout = 0;
}
}
+
static gboolean
check_model_dnd (GtkTreeModel *model,
GType required_iface,
gtk_tree_view_vertical_autoscroll (tree_view);
+ if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+ gtk_tree_view_update_rubber_band (tree_view);
+
GDK_THREADS_LEAVE ();
return TRUE;
GtkTreePath *path = NULL;
gint cell_x, cell_y;
GdkPixmap *row_pix;
+ TreeViewDragInfo *di;
tree_view = GTK_TREE_VIEW (widget);
- /* if the user uses a custom DnD impl, we don't set the icon here */
- if (!get_info (tree_view))
+ /* if the user uses a custom DND source impl, we don't set the icon here */
+ di = get_info (tree_view);
+
+ if (di == NULL || !di->source_set)
return;
gtk_tree_view_get_path_at_pos (tree_view,
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)
{
for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
- break;
-
- tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+ {
+ tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
+ break;
+ }
/* If the following isn't true, then the view is smaller then the scrollpane.
*/
static void
gtk_tree_view_grab_focus (GtkWidget *widget)
{
- (* GTK_WIDGET_CLASS (parent_class)->grab_focus) (widget);
+ (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus) (widget);
gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
}
if (GTK_WIDGET_REALIZED (widget))
{
- gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+ gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+
+ gtk_tree_view_set_grid_lines (tree_view, tree_view->priv->grid_lines);
+ gtk_tree_view_set_enable_tree_lines (tree_view, tree_view->priv->tree_lines_enabled);
}
gtk_widget_style_get (widget,
}
}
- (* parent_class->set_focus_child) (container, child);
+ GTK_CONTAINER_CLASS (gtk_tree_view_parent_class)->set_focus_child (container, child);
}
static void
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),
gint i = 0;
gint height;
gboolean free_path = FALSE;
+ gboolean node_visible = TRUE;
g_return_if_fail (path != NULL || iter != NULL);
if (tmptree == NULL)
{
/* We aren't showing the node */
+ node_visible = FALSE;
goto done;
}
}
if (tree == NULL)
- goto done;
+ {
+ node_visible = FALSE;
+ goto done;
+ }
/* ref the node */
gtk_tree_model_ref_node (tree_view->priv->model, iter);
if (indices[depth - 1] == 0)
{
tmpnode = _gtk_rbtree_find_count (tree, 1);
- _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
+ tmpnode = _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
}
else
{
tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
- _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
- }
+ tmpnode = _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);
+
+ if (node_visible && node_is_visible (tree_view, tree, tmpnode))
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ else
+ gtk_widget_queue_resize_no_redraw (GTK_WIDGET (tree_view));
+ }
else
install_presize_handler (tree_view);
if (free_path)
else
x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
}
- if (x1)
- {
- *x1 = x_offset;
- }
+ *x1 = x_offset;
+
if (tmp_column && tmp_column->visible)
- {
- /* +1 because x2 isn't included in the range. */
- if (x2)
- *x2 = *x1 + tree_view->priv->expander_size + 1;
- }
+ /* +1 because x2 isn't included in the range. */
+ *x2 = *x1 + tree_view->priv->expander_size + 1;
else
- {
- /* return an empty range, the expander column is hidden */
- if (x2)
- *x2 = *x1;
- }
+ *x2 = *x1;
}
static void
gboolean recurse)
{
GtkRBNode *temp = NULL;
+ GtkTreePath *path = NULL;
gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
do
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)
{
GtkTreeIter child;
+ if (!path)
+ path = gtk_tree_model_get_path (tree_view->priv->model, iter);
+ else
+ gtk_tree_path_next (path);
+
if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
{
- temp->children = _gtk_rbtree_new ();
- temp->children->parent_tree = tree;
- temp->children->parent_node = temp;
- gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
+ gboolean expand;
+
+ g_signal_emit (tree_view, tree_view_signals[TEST_EXPAND_ROW], 0, &iter, path, &expand);
+
+ if (!expand)
+ {
+ temp->children = _gtk_rbtree_new ();
+ temp->children->parent_tree = tree;
+ temp->children->parent_node = temp;
+ gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
+ }
}
}
+
if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
{
if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
}
}
while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
+
+ if (path)
+ gtk_tree_path_free (path);
}
/* If height is non-NULL, then we set it to be the new height. if it's all
&width, NULL);
}
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ if (gtk_tree_view_is_expander_column (tree_view, column))
{
- if (depth * tree_view->priv->expander_size + horizontal_separator + width > column->requested_width)
+ int tmp = 0;
+
+ tmp = horizontal_separator + width + (depth - 1) * tree_view->priv->level_indentation;
+ if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ tmp += depth * tree_view->priv->expander_size;
+
+ if (tmp > column->requested_width)
{
_gtk_tree_view_column_cell_set_dirty (column, TRUE);
retval = TRUE;
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.
gtk_tree_view_add_move_binding (GtkBindingSet *binding_set,
guint keyval,
guint modmask,
+ gboolean add_shifted_binding,
GtkMovementStep step,
gint count)
{
G_TYPE_ENUM, step,
G_TYPE_INT, count);
- gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
- "move_cursor", 2,
- G_TYPE_ENUM, step,
- G_TYPE_INT, count);
+ if (add_shifted_binding)
+ gtk_binding_entry_add_signal (binding_set, keyval, GDK_SHIFT_MASK,
+ "move_cursor", 2,
+ G_TYPE_ENUM, step,
+ G_TYPE_INT, count);
if ((modmask & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
return;
/* We know there are always 2 slots possbile, as you can always return column. */
/* If that's all there is, return */
- if (tree_view->priv->column_drag_info->next->next == NULL &&
- ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
- ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
+ if (tree_view->priv->column_drag_info->next == NULL ||
+ (tree_view->priv->column_drag_info->next->next == NULL &&
+ ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
+ ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column))
{
for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
g_free (tmp_list->data);
return;
rect.x = 0;
- rect.width = MAX (tree_view->priv->expander_size, GTK_WIDGET (tree_view)->allocation.width);
+ rect.width = MAX (tree_view->priv->expander_size, MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width));
rect.y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
rect.height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node));
GtkStateType state;
GtkWidget *widget;
gint x_offset = 0;
+ gint x2;
gint vertical_separator;
gint expander_size;
GtkExpanderStyle expander_style;
widget = GTK_WIDGET (tree_view);
- gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
+ gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, &x2);
area.x = x_offset;
area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
gint count)
{
+ gint selection_count;
GtkRBTree *cursor_tree = NULL;
GtkRBNode *cursor_node = NULL;
GtkRBTree *new_cursor_tree = NULL;
if (cursor_tree == NULL)
/* FIXME: we lost the cursor; should we get the first? */
return;
- if (count == -1)
- _gtk_rbtree_prev_full (cursor_tree, cursor_node,
- &new_cursor_tree, &new_cursor_node);
+
+ selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
+
+ if (selection_count == 0 && !tree_view->priv->ctrl_pressed)
+ {
+ new_cursor_tree = cursor_tree;
+ new_cursor_node = cursor_node;
+ }
else
- _gtk_rbtree_next_full (cursor_tree, cursor_node,
- &new_cursor_tree, &new_cursor_node);
+ {
+ if (count == -1)
+ _gtk_rbtree_prev_full (cursor_tree, cursor_node,
+ &new_cursor_tree, &new_cursor_node);
+ else
+ _gtk_rbtree_next_full (cursor_tree, cursor_node,
+ &new_cursor_tree, &new_cursor_node);
+ }
/*
* If the list has only one item and multi-selection is set then select
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
}
gtk_tree_path_free (cursor_path);
- list = tree_view->priv->columns;
+ list = rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns);
if (tree_view->priv->focus_column)
{
- for (list = tree_view->priv->columns; list; list = list->next)
+ for (; list; list = (rtl ? list->prev : list->next))
{
if (list->data == tree_view->priv->focus_column)
break;
while (list)
{
+ gboolean left, right;
+
column = list->data;
if (column->visible == FALSE)
goto loop_end;
&iter,
GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
cursor_node->children?TRUE:FALSE);
- if (_gtk_tree_view_column_cell_focus (column, count,
- list->prev?TRUE:FALSE,
- list->next?TRUE:FALSE))
+
+ if (rtl)
+ {
+ right = list->prev ? TRUE : FALSE;
+ left = list->next ? TRUE : FALSE;
+ }
+ else
+ {
+ left = list->prev ? TRUE : FALSE;
+ right = list->next ? TRUE : FALSE;
+ }
+
+ if (_gtk_tree_view_column_cell_focus (column, count, left, right))
{
tree_view->priv->focus_column = column;
found_column = TRUE;
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 */
{
GtkWidget *frame, *vbox, *toplevel;
+ if (tree_view->priv->search_custom_entry_set)
+ return;
+
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
if (tree_view->priv->search_window != NULL)
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 (tree_view->priv->search_custom_entry_set)
+ return FALSE;
+
if (tree_view->priv->search_window != NULL &&
GTK_WIDGET_VISIBLE (tree_view->priv->search_window))
return TRUE;
gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
/* done, show it */
- tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+ tree_view->priv->search_position_func (tree_view, tree_view->priv->search_window, tree_view->priv->search_position_user_data);
gtk_widget_show (tree_view->priv->search_window);
if (tree_view->priv->search_entry_changed_id == 0)
{
{
return gtk_tree_view_real_start_interactive_search (tree_view, TRUE);
}
+
/* this function returns the new width of the column being resized given
* the column and x position of the cursor; the x cursor position is passed
* in as a pointer and automagicly corrected if it's beyond min/max limits
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.
+ *
+ * Returns whether all header columns are clickable.
+ *
+ * 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) &&
* Creates a new #GtkTreeViewColumn and inserts it into the @tree_view at
* @position. If @position is -1, then the newly created column is inserted at
* the end. The column is initialized with the attributes given. If @tree_view
- * has "fixed_height" mode enabled, then @column must have its sizing
+ * has "fixed_height" mode enabled, then the new column will have its sizing
* property set to be GTK_TREE_VIEW_COLUMN_FIXED.
*
* Return value: The number of columns in @tree_view after insertion.
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
column = gtk_tree_view_column_new ();
+ if (tree_view->priv->fixed_height_mode)
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_title (column, title);
gtk_tree_view_column_pack_start (column, cell, TRUE);
* with the given cell renderer and a #GtkCellDataFunc to set cell renderer
* attributes (normally using data from the model). See also
* gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
- * If @tree_view has "fixed_height" mode enabled, then @column must have its
+ * If @tree_view has "fixed_height" mode enabled, then the new column will have its
* "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
*
* Return value: number of columns in the tree view post-insert
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), -1);
column = gtk_tree_view_column_new ();
+ if (tree_view->priv->fixed_height_mode)
+ gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_column_set_title (column, title);
gtk_tree_view_column_pack_start (column, cell, TRUE);
* it is much slower than just going to the point.
*/
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))
{
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);
rect->height = MAX (CELL_HEIGHT (node, vertical_separator), tree_view->priv->expander_size - vertical_separator);
if (column &&
- gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ gtk_tree_view_is_expander_column (tree_view, column))
{
- gint depth = gtk_tree_path_get_depth (path) - 1;
+ gint depth = gtk_tree_path_get_depth (path);
+ gboolean rtl;
+
+ rtl = gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL;
+
+ if (!rtl)
+ rect->x += (depth - 1) * tree_view->priv->level_indentation;
+ rect->width -= (depth - 1) * tree_view->priv->level_indentation;
+
+ if (TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ {
+ if (!rtl)
+ rect->x += depth * tree_view->priv->expander_size;
+ rect->width -= depth * tree_view->priv->expander_size;
+ }
- rect->x += depth * tree_view->priv->expander_size;
- rect->width -= depth * tree_view->priv->expander_size;
rect->width = MAX (rect->width, 0);
}
}
*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)
{
* @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.
**/
GdkDrawable *drawable;
gint bin_window_width;
gboolean is_separator = FALSE;
+ gboolean rtl;
+
+ 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,
bin_window_width + 2,
background_area.height + 2);
- 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))
{
GtkTreeViewColumn *column = list->data;
GdkRectangle cell_area;
background_area.x = cell_offset;
background_area.width = column->width;
+ gtk_widget_style_get (widget,
+ "vertical-separator", &vertical_separator,
+ NULL);
+
cell_area = background_area;
- gtk_widget_style_get (widget, "vertical-separator", &vertical_separator, NULL);
cell_area.y += vertical_separator / 2;
cell_area.height -= vertical_separator;
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS(tree_view))
+ if (gtk_tree_view_is_expander_column (tree_view, column))
{
- cell_area.x += depth * tree_view->priv->expander_size;
- cell_area.width -= depth * tree_view->priv->expander_size;
+ if (!rtl)
+ cell_area.x += (depth - 1) * tree_view->priv->level_indentation;
+ cell_area.width -= (depth - 1) * tree_view->priv->level_indentation;
+
+ if (TREE_VIEW_DRAW_EXPANDERS(tree_view))
+ {
+ if (!rtl)
+ cell_area.x += depth * tree_view->priv->expander_size;
+ cell_area.width -= depth * tree_view->priv->expander_size;
+ }
}
if (gtk_tree_view_column_cell_is_visible (column))
GtkDestroyNotify search_destroy)
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_return_if_fail (search_equal_func !=NULL);
+ g_return_if_fail (search_equal_func != NULL);
if (tree_view->priv->search_destroy)
(* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
}
+/**
+ * gtk_tree_view_get_search_entry:
+ * @tree_view: A #GtkTreeView
+ *
+ * Returns the GtkEntry which is currently in use as interactive search
+ * entry for @tree_view. In case the built-in entry is being used, %NULL
+ * will be returned.
+ *
+ * Return value: the entry currently in use as search entry.
+ *
+ * Since: 2.10
+ */
+GtkEntry *
+gtk_tree_view_get_search_entry (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ if (tree_view->priv->search_custom_entry_set)
+ return GTK_ENTRY (tree_view->priv->search_entry);
+
+ return NULL;
+}
+
+/**
+ * gtk_tree_view_set_search_entry:
+ * @tree_view: A #GtkTreeView
+ * @entry: the entry the interactive search code of @tree_view should use or %NULL
+ *
+ * Sets the entry which the interactive search code will use for this
+ * @tree_view. This is useful when you want to provide a search entry
+ * in our interface at all time at a fixed position. Passing %NULL for
+ * @entry will make the interactive search code use the built-in popup
+ * entry again.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_search_entry (GtkTreeView *tree_view,
+ GtkEntry *entry)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ if (entry != NULL)
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+
+ if (tree_view->priv->search_custom_entry_set)
+ {
+ if (tree_view->priv->search_entry_changed_id)
+ {
+ g_signal_handler_disconnect (tree_view->priv->search_entry,
+ tree_view->priv->search_entry_changed_id);
+ tree_view->priv->search_entry_changed_id = 0;
+ }
+ g_signal_handlers_disconnect_by_func (tree_view->priv->search_entry,
+ G_CALLBACK (gtk_tree_view_search_key_press_event),
+ tree_view);
+
+ g_object_unref (tree_view->priv->search_entry);
+ }
+ else if (tree_view->priv->search_window)
+ {
+ gtk_widget_destroy (tree_view->priv->search_window);
+
+ tree_view->priv->search_window = NULL;
+ }
+
+ if (entry)
+ {
+ tree_view->priv->search_entry = g_object_ref (entry);
+ tree_view->priv->search_custom_entry_set = TRUE;
+
+ if (tree_view->priv->search_entry_changed_id == 0)
+ {
+ tree_view->priv->search_entry_changed_id =
+ g_signal_connect (tree_view->priv->search_entry, "changed",
+ G_CALLBACK (gtk_tree_view_search_init),
+ tree_view);
+ }
+
+ g_signal_connect (tree_view->priv->search_entry, "key_press_event",
+ G_CALLBACK (gtk_tree_view_search_key_press_event),
+ tree_view);
+
+ gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
+ }
+ else
+ {
+ tree_view->priv->search_entry = NULL;
+ tree_view->priv->search_custom_entry_set = FALSE;
+ }
+}
+
+/**
+ * gtk_tree_view_set_search_position_func:
+ * @tree_view: A #GtkTreeView
+ * @func: the function to use to position the search dialog, or %NULL
+ * to use the default search position function
+ * @data: user data to pass to @func, or %NULL
+ * @destroy: Destroy notifier for @data, or %NULL
+ *
+ * Sets the function to use when positioning the seach dialog.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_tree_view_set_search_position_func (GtkTreeView *tree_view,
+ GtkTreeViewSearchPositionFunc func,
+ gpointer user_data,
+ GDestroyNotify destroy)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tree_view->priv->search_position_destroy)
+ (* tree_view->priv->search_position_destroy) (tree_view->priv->search_position_user_data);
+
+ tree_view->priv->search_position_func = func;
+ tree_view->priv->search_position_user_data = user_data;
+ tree_view->priv->search_position_destroy = destroy;
+ if (tree_view->priv->search_position_func == NULL)
+ tree_view->priv->search_position_func = gtk_tree_view_search_position_func;
+}
+
+/**
+ * gtk_tree_view_get_search_position_func:
+ * @tree_view: A #GtkTreeView
+ *
+ * Returns the positioning function currently in use.
+ *
+ * Return value: the currently used function for positioning the search dialog.
+ *
+ * Since: 2.10
+ */
+GtkTreeViewSearchPositionFunc
+gtk_tree_view_get_search_position_func (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->search_position_func;
+}
+
+
static void
gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
GtkTreeView *tree_view)
static void
gtk_tree_view_search_position_func (GtkTreeView *tree_view,
- GtkWidget *search_dialog)
+ GtkWidget *search_dialog,
+ gpointer user_data)
{
gint x, y;
gint tree_x, tree_y;
&tree_height);
gtk_widget_size_request (search_dialog, &requisition);
- if (tree_x + tree_width - requisition.width > gdk_screen_get_width (screen))
+ if (tree_x + tree_width > gdk_screen_get_width (screen))
x = gdk_screen_get_width (screen) - requisition.width;
else if (tree_x + tree_width - requisition.width < 0)
x = 0;
else
x = tree_x + tree_width - requisition.width;
- if (tree_y + tree_height > gdk_screen_get_height (screen))
+ if (tree_y + tree_height + requisition.height > gdk_screen_get_height (screen))
y = gdk_screen_get_height (screen) - requisition.height;
else if (tree_y + tree_height < 0) /* isn't really possible ... */
y = 0;
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,
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
/* close window and cancel the search */
- if (event->keyval == GDK_Escape ||
- event->keyval == GDK_Tab)
+ if (!tree_view->priv->search_custom_entry_set
+ && (event->keyval == GDK_Escape ||
+ 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)
+ if (retval && tree_view->priv->typeselect_flush_timeout
+ && !tree_view->priv->search_custom_entry_set)
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
/* search */
gtk_tree_selection_unselect_all (selection);
- if (tree_view->priv->typeselect_flush_timeout)
+ if (tree_view->priv->typeselect_flush_timeout
+ && tree_view->priv->search_custom_entry_set)
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
tree_view->priv->focus_column,
&cell_area);
- if (gtk_tree_view_is_expander_column (tree_view, tree_view->priv->focus_column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
- {
- cell_area.x += tree_view->priv->expander_size;
- cell_area.width -= tree_view->priv->expander_size;
- }
-
if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
&editable_widget,
NULL,
area = cell_area;
cell = _gtk_tree_view_column_get_edited_cell (tree_view->priv->focus_column);
+
_gtk_tree_view_column_get_neighbor_sizes (tree_view->priv->focus_column, cell, &left, &right);
area.x += left;
return tree_view->priv->hover_expand;
}
+/**
+ * gtk_tree_view_set_rubber_banding:
+ * @tree_view: a #GtkTreeView
+ * @enable: %TRUE to enable rubber banding
+ *
+ * Enables or disables rubber banding in @tree_view. If the selection mode
+ * is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
+ * multiple rows by dragging the mouse.
+ *
+ * Since: 2.10
+ **/
+void
+gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
+ gboolean enable)
+{
+ enable = enable != FALSE;
+
+ if (enable != tree_view->priv->rubber_banding_enable)
+ {
+ tree_view->priv->rubber_banding_enable = enable;
+
+ g_object_notify (G_OBJECT (tree_view), "rubber-banding");
+ }
+}
+
+/**
+ * gtk_tree_view_get_rubber_banding:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns whether rubber banding is turned on for @tree_view. If the
+ * selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
+ * user to select multiple rows by dragging the mouse.
+ *
+ * Return value: %TRUE if rubber banding in @tree_view is enabled.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
+{
+ return tree_view->priv->rubber_banding_enable;
+}
+
/**
* gtk_tree_view_get_row_separator_func:
* @tree_view: a #GtkTreeView
if (GTK_WIDGET_REALIZED (widget))
{
- gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+ gdk_window_set_back_pixmap (widget->window, NULL, FALSE);
gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
}
gtk_widget_queue_draw (widget);
}
+/**
+ * gtk_tree_view_get_grid_lines:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns which grid lines are enabled in @tree_view.
+ *
+ * Return value: a #GtkTreeViewGridLines value indicating which grid lines
+ * are enabled.
+ *
+ * Since: 2.10
+ */
+GtkTreeViewGridLines
+gtk_tree_view_get_grid_lines (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return tree_view->priv->grid_lines;
+}
+
+/**
+ * gtk_tree_view_set_grid_lines:
+ * @tree_view: a #GtkTreeView
+ * @grid_lines: a #GtkTreeViewGridLines value indicating which grid lines to
+ * enable.
+ *
+ * Sets which grid lines to draw in @tree_view.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_grid_lines (GtkTreeView *tree_view,
+ GtkTreeViewGridLines grid_lines)
+{
+ gint line_width;
+ guint8 *dash_list;
+ GtkWidget *widget;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ widget = GTK_WIDGET (tree_view);
+
+ if (!GTK_WIDGET_REALIZED (widget))
+ {
+ tree_view->priv->grid_lines = grid_lines;
+ return;
+ }
+
+ gtk_widget_style_get (widget,
+ "grid-line-width", &line_width,
+ "grid-line-pattern", (gchar *)&dash_list,
+ NULL);
+
+ if (tree_view->priv->grid_line_gc)
+ g_object_unref (tree_view->priv->grid_line_gc);
+
+ tree_view->priv->grid_lines = grid_lines;
+ if (grid_lines == GTK_TREE_VIEW_GRID_LINES_NONE)
+ {
+ tree_view->priv->grid_line_gc = NULL;
+ g_free (dash_list);
+ return;
+ }
+
+ tree_view->priv->grid_line_gc = gdk_gc_new (widget->window);
+ gdk_gc_copy (tree_view->priv->grid_line_gc,
+ widget->style->black_gc);
+
+ gdk_gc_set_line_attributes (tree_view->priv->grid_line_gc, line_width,
+ GDK_LINE_ON_OFF_DASH,
+ GDK_CAP_BUTT, GDK_JOIN_MITER);
+ gdk_gc_set_dashes (tree_view->priv->grid_line_gc, 0, dash_list, 2);
+ g_free (dash_list);
+
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_enable_tree_lines:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns whether or not tree lines are drawn in @tree_view.
+ *
+ * Return value: %TRUE if tree lines are drawn in @tree_view, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ */
+gboolean
+gtk_tree_view_get_enable_tree_lines (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ return tree_view->priv->tree_lines_enabled;
+}
+
+/**
+ * gtk_tree_view_set_enable_tree_lines:
+ * @tree_view: a #GtkTreeView
+ * @enabled: %TRUE to enable tree line drawing, %FALSE otherwise.
+ *
+ * Sets whether to draw lines interconnecting the expanders in @tree_view.
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.10
+ */
+void
+gtk_tree_view_set_enable_tree_lines (GtkTreeView *tree_view,
+ gboolean enabled)
+{
+ gint line_width;
+ guint8 *dash_list;
+ GtkWidget *widget;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ widget = GTK_WIDGET (tree_view);
+
+ if (!GTK_WIDGET_REALIZED (widget))
+ {
+ tree_view->priv->tree_lines_enabled = enabled;
+ return;
+ }
+
+ gtk_widget_style_get (widget,
+ "tree-line-width", &line_width,
+ "tree-line-pattern", (gchar *)&dash_list,
+ NULL);
+
+ if (tree_view->priv->tree_line_gc)
+ g_object_unref (tree_view->priv->tree_line_gc);
+
+ if (!enabled)
+ {
+ tree_view->priv->tree_line_gc = NULL;
+ return;
+ }
+
+ tree_view->priv->tree_line_gc = gdk_gc_new (widget->window);
+ gdk_gc_copy (tree_view->priv->tree_line_gc,
+ widget->style->black_gc);
+
+ gdk_gc_set_line_attributes (tree_view->priv->tree_line_gc, line_width,
+ GDK_LINE_ON_OFF_DASH,
+ GDK_CAP_BUTT, GDK_JOIN_MITER);
+ gdk_gc_set_dashes (tree_view->priv->tree_line_gc, 0, dash_list, 2);
+
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"