#include "gtkcellrenderer.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
+#include "gtkbuildable.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
#include "gtkentry.h"
#include "gtkframe.h"
#include "gtktreemodelsort.h"
+#include "gtktooltip.h"
#include "gtkprivate.h"
#include "gtkalias.h"
#define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
#define CELL_HEIGHT(node, separator) ((BACKGROUND_HEIGHT (node)) - (separator))
+/* Translate from bin_window coordinates to rbtree (tree coordinates) and
+ * vice versa.
+ */
#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) + tree_view->priv->dy)
#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) - tree_view->priv->dy)
-/* This is in Window coordinates */
+/* This is in bin_window coordinates */
#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
PROP_LEVEL_INDENTATION,
PROP_RUBBER_BANDING,
PROP_ENABLE_GRID_LINES,
- PROP_ENABLE_TREE_LINES
+ PROP_ENABLE_TREE_LINES,
+ PROP_TOOLTIP_COLUMN
};
/* object signals */
static gboolean presize_handler_callback (gpointer data);
static void install_presize_handler (GtkTreeView *tree_view);
static void install_scroll_sync_handler (GtkTreeView *tree_view);
+static void gtk_tree_view_set_top_row (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ gint offset);
static void gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view);
static void gtk_tree_view_top_row_to_dy (GtkTreeView *tree_view);
static void invalidate_empty_focus (GtkTreeView *tree_view);
GtkRBTree *tree,
GtkRBNode *node);
static void gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view,
- GtkTreeViewColumn *column);
+ GtkTreeViewColumn *column,
+ gboolean focus_to_cell);
static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
GdkEventMotion *event);
static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view);
static gboolean gtk_tree_view_search_key_press_event (GtkWidget *entry,
GdkEventKey *event,
GtkTreeView *tree_view);
-static void gtk_tree_view_search_move (GtkWidget *window,
+static gboolean gtk_tree_view_search_move (GtkWidget *window,
GtkTreeView *tree_view,
gboolean up);
static gboolean gtk_tree_view_search_equal_func (GtkTreeModel *model,
GtkTreeViewColumn *column,
gint drop_position);
-static void gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty);
+/* GtkBuildable */
+static void gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type);
+static void gtk_tree_view_buildable_init (GtkBuildableIface *iface);
-static gint scroll_row_timeout (gpointer data);
-static void remove_scroll_timeout (GtkTreeView *tree_view);
+
+static gboolean scroll_row_timeout (gpointer data);
+static void add_scroll_timeout (GtkTreeView *tree_view);
+static void remove_scroll_timeout (GtkTreeView *tree_view);
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
/* GType Methods
*/
-G_DEFINE_TYPE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE_WITH_CODE (GtkTreeView, gtk_tree_view, GTK_TYPE_CONTAINER,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_view_buildable_init))
static void
gtk_tree_view_class_init (GtkTreeViewClass *class)
FALSE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkTreeView:show-expanders:
+ *
+ * %TRUE if the view has expanders.
+ *
+ * Since: 2.12
+ */
g_object_class_install_property (o_class,
PROP_SHOW_EXPANDERS,
g_param_spec_boolean ("show-expanders",
TRUE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkTreeView:level-indentation:
+ *
+ * Extra indentation for each level.
+ *
+ * Since: 2.12
+ */
g_object_class_install_property (o_class,
PROP_LEVEL_INDENTATION,
g_param_spec_int ("level-indentation",
FALSE,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (o_class,
+ PROP_TOOLTIP_COLUMN,
+ g_param_spec_int ("tooltip-column",
+ P_("Tooltip Column"),
+ P_("The column in the model containing the tooltip texts for the rows"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+
/* Style properties */
#define _TREE_VIEW_EXPANDER_SIZE 12
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
* 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
+ * Returns: %FALSE to allow expansion, %TRUE to reject
*/
tree_view_signals[TEST_EXPAND_ROW] =
g_signal_new (I_("test-expand-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
+ * Returns: %FALSE to allow collapsing, %TRUE to reject
*/
tree_view_signals[TEST_COLLAPSE_ROW] =
g_signal_new (I_("test-collapse-row"),
GTK_MOVEMENT_PAGES, 1);
- gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "move_cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "move_cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, -1);
-
- gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "move_cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, 1);
-
- gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "move_cursor", 2,
- G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
- G_TYPE_INT, -1);
-
gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
"move_cursor", 2,
G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, 0, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, 0, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE);
+
+
gtk_binding_entry_add_signal (binding_set, GDK_asterisk, 0,
"expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, FALSE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, 0, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, FALSE);
gtk_binding_entry_add_signal (binding_set, GDK_minus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, FALSE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, 0, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, FALSE);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE,
g_type_class_add_private (o_class, sizeof (GtkTreeViewPrivate));
}
+static void
+gtk_tree_view_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add_child = gtk_tree_view_buildable_add_child;
+}
+
static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
/* We need some padding */
tree_view->priv->dy = 0;
+ tree_view->priv->cursor_offset = 0;
tree_view->priv->n_columns = 0;
tree_view->priv->header_height = 1;
tree_view->priv->x_drag = 0;
tree_view->priv->grid_lines = GTK_TREE_VIEW_GRID_LINES_NONE;
tree_view->priv->tree_lines_enabled = FALSE;
+
+ tree_view->priv->tooltip_column = -1;
}
\f
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);
+ gtk_tree_view_set_show_expanders (tree_view, g_value_get_boolean (value));
break;
case PROP_LEVEL_INDENTATION:
tree_view->priv->level_indentation = g_value_get_int (value);
case PROP_ENABLE_TREE_LINES:
gtk_tree_view_set_enable_tree_lines (tree_view, g_value_get_boolean (value));
break;
+ case PROP_TOOLTIP_COLUMN:
+ gtk_tree_view_set_tooltip_column (tree_view, g_value_get_int (value));
+ break;
default:
break;
}
case PROP_ENABLE_TREE_LINES:
g_value_set_boolean (value, tree_view->priv->tree_lines_enabled);
break;
+ case PROP_TOOLTIP_COLUMN:
+ g_value_set_boolean (value, tree_view->priv->tooltip_column);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
\f
+static void
+gtk_tree_view_buildable_add_child (GtkBuildable *tree_view,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *type)
+{
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), GTK_TREE_VIEW_COLUMN (child));
+}
+
/* GtkObject Methods
*/
priv->scroll_timeout = 0;
}
+ if (priv->auto_expand_timeout != 0)
+ {
+ g_source_remove (priv->auto_expand_timeout);
+ priv->auto_expand_timeout = 0;
+ }
+
if (priv->open_dest_timeout != 0)
{
g_source_remove (priv->open_dest_timeout);
coords_are_over_arrow (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
- /* these are in window coords */
+ /* these are in bin window coords */
gint x,
gint y)
{
GtkTreeView *tree_view = GTK_TREE_VIEW (data);
GtkTreePath *path;
- GDK_THREADS_ENTER ();
-
if (tree_view->priv->prelight_node)
{
path = _gtk_tree_view_find_path (tree_view,
tree_view->priv->auto_expand_timeout = 0;
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
do_prelight (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
- /* these are in tree_window coords */
+ /* these are in bin_window coords */
gint x,
gint y)
{
if (tree_view->priv->hover_expand)
{
tree_view->priv->auto_expand_timeout =
- g_timeout_add (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
+ gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, auto_expand_timeout, tree_view);
}
}
prelight_or_select (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
- /* these are in tree_window coords */
+ /* these are in bin_window coords */
gint x,
gint y)
{
{
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);
- }
+ add_scroll_timeout (tree_view);
}
/* only check for an initiated drag when a button is pressed */
* less messy way).
*/
if (is_first && is_last)
- snprintf (new_detail, 127, "%s", detail);
+ g_snprintf (new_detail, 127, "%s", detail);
else if (is_first)
- snprintf (new_detail, 127, "%s_start", detail);
+ g_snprintf (new_detail, 127, "%s_start", detail);
else if (is_last)
- snprintf (new_detail, 127, "%s_end", detail);
+ g_snprintf (new_detail, 127, "%s_end", detail);
else
- snprintf (new_detail, 128, "%s_middle", detail);
+ g_snprintf (new_detail, 128, "%s_middle", detail);
gtk_paint_flat_box (widget->style,
event->window,
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
GTK_WIDGET_STATE (widget),
- NULL,
+ &event->area,
widget,
(is_first
? (is_last ? "treeview-drop-indicator" : "treeview-drop-indicator-left" )
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
GTK_WIDGET_STATE (widget),
- NULL,
+ &event->area,
widget,
"treeview-drop-indicator",
0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node)
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
focus_rect_state,
- NULL,
+ &event->area,
widget,
(is_first
? (is_last ? "treeview" : "treeview-left" )
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
focus_rect_state,
- NULL,
+ &event->area,
widget,
"treeview",
0, tmp_y,
{
GtkTreeView *tree_view = (GtkTreeView *) widget;
+ if (tree_view->priv->rubber_band_status)
+ {
+ if (event->keyval == GDK_Escape)
+ gtk_tree_view_stop_rubber_band (tree_view);
+
+ return TRUE;
+ }
+
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
{
if (event->keyval == GDK_Escape)
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
{
GList *focus_column;
- gint focus_column_width = 0;
gboolean rtl;
rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
if (GTK_WIDGET_HAS_FOCUS (column->button))
break;
-
- if (column->visible)
- focus_column_width += GTK_TREE_VIEW_COLUMN (column)->width;
}
if (focus_column &&
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (focus_column->data);
if (!column->resizable)
- return TRUE;
+ {
+ gtk_widget_error_bell (widget);
+ return TRUE;
+ }
if (event->keyval == (rtl ? GDK_Right : GDK_Left)
|| event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
{
+ gint old_width = column->resized_width;
+
column->resized_width = MAX (column->resized_width,
column->width);
column->resized_width -= 2;
column->max_width);
column->use_resized_width = TRUE;
- gtk_widget_queue_resize (widget);
+
+ if (column->resized_width != old_width)
+ gtk_widget_queue_resize (widget);
+ else
+ gtk_widget_error_bell (widget);
}
else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
|| event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
{
+ gint old_width = column->resized_width;
+
column->resized_width = MAX (column->resized_width,
column->width);
column->resized_width += 2;
column->max_width);
column->use_resized_width = TRUE;
- gtk_widget_queue_resize (widget);
+
+ if (column->resized_width != old_width)
+ gtk_widget_queue_resize (widget);
+ else
+ gtk_widget_error_bell (widget);
}
return TRUE;
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
if (col != (GtkTreeViewColumn *)0x1)
gtk_tree_view_move_column_after (tree_view, column, col);
+ else
+ gtk_widget_error_bell (widget);
}
else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
|| event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
if (col != (GtkTreeViewColumn *)0x1)
gtk_tree_view_move_column_after (tree_view, column, col);
+ else
+ gtk_widget_error_bell (widget);
}
else if (event->keyval == GDK_Home || event->keyval == GDK_KP_Home)
{
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
if (col != (GtkTreeViewColumn *)0x1)
gtk_tree_view_move_column_after (tree_view, column, col);
+ else
+ gtk_widget_error_bell (widget);
}
else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
{
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
if (col != (GtkTreeViewColumn *)0x1)
gtk_tree_view_move_column_after (tree_view, column, col);
- }
-
- return TRUE;
- }
-
- if (focus_column &&
- (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
- || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
- {
- if ((event->keyval == (rtl ? GDK_Right : GDK_Left)
- || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
- && focus_column->prev)
- {
- GList *tmp;
-
- for (tmp = focus_column->prev; tmp; tmp = tmp->prev)
- if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
- break;
-
- if (!tmp)
- return FALSE;
-
- tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
- gtk_widget_grab_focus (tree_view->priv->focus_column->button);
- focus_column_width -= tree_view->priv->focus_column->width;
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- CLAMP (focus_column_width,
- tree_view->priv->hadjustment->lower,
- tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
- }
- else if ((event->keyval == (rtl ? GDK_Left : GDK_Right)
- || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
- && focus_column->next)
- {
- GList *tmp;
-
- for (tmp = focus_column->next; tmp; tmp = tmp->next)
- if (GTK_TREE_VIEW_COLUMN (tmp->data)->visible)
- break;
-
- if (!tmp)
- return FALSE;
-
- tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (tmp->data);
-
- gtk_widget_grab_focus (tree_view->priv->focus_column->button);
- focus_column_width += tree_view->priv->focus_column->width;
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- CLAMP (focus_column_width,
- tree_view->priv->hadjustment->lower,
- tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
+ else
+ gtk_widget_error_bell (widget);
}
return TRUE;
gtk_tree_view_key_release (GtkWidget *widget,
GdkEventKey *event)
{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+ if (tree_view->priv->rubber_band_status)
+ return TRUE;
+
return (* GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->key_release_event) (widget, event);
}
else
{
/* row not visible */
- if (dy >= 0 && dy <= tree_view->priv->vadjustment->page_size)
+ if (dy >= 0
+ && dy + height <= tree_view->priv->vadjustment->page_size)
{
/* row at the beginning -- fixed */
area_above = dy;
- area_above - height;
}
else if (dy >= (tree_view->priv->vadjustment->upper -
- tree_view->priv->vadjustment->page_size)
- && dy <= tree_view->priv->vadjustment->upper)
+ tree_view->priv->vadjustment->page_size))
{
/* row at the end -- fixed */
area_above = dy - (tree_view->priv->vadjustment->upper -
if (area_below < 0)
{
- area_above += area_below;
+ area_above = tree_view->priv->vadjustment->page_size - height;
area_below = 0;
}
}
*/
if (area_above == 0)
{
- GtkRBTree *tree;
- GtkRBNode *node;
- GtkTreePath *tmppath;
- GtkTreeIter iter;
+ GtkRBTree *tmptree;
+ GtkRBNode *tmpnode;
- _gtk_tree_view_find_node (tree_view, above_path, &tree, &node);
+ _gtk_tree_view_find_node (tree_view, above_path, &tmptree, &tmpnode);
+ _gtk_rbtree_prev_full (tmptree, tmpnode, &tmptree, &tmpnode);
- tmppath = gtk_tree_path_copy (above_path);
-
- _gtk_rbtree_prev_full (tree, node, &tree, &node);
- if (! gtk_tree_path_prev (tmppath) && node != NULL)
+ if (tmpnode)
{
- gtk_tree_path_free (tmppath);
- tmppath = _gtk_tree_view_find_path (tree_view, tree, node);
- }
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, tmppath);
+ GtkTreePath *tmppath;
+ GtkTreeIter tmpiter;
- if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
- GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
- {
- _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
- if (validate_row (tree_view, tree, node, &iter, path))
- size_changed = TRUE;
- }
+ tmppath = _gtk_tree_view_find_path (tree_view, tmptree, tmpnode);
+ gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, tmppath);
+
+ if (GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (tmpnode, GTK_RBNODE_COLUMN_INVALID))
+ {
+ _gtk_tree_view_queue_draw_node (tree_view, tmptree, tmpnode, NULL);
+ if (validate_row (tree_view, tmptree, tmpnode, &tmpiter, tmppath))
+ size_changed = TRUE;
+ }
- gtk_tree_path_free (tmppath);
+ gtk_tree_path_free (tmppath);
+ }
}
/* Now, we walk forwards and backwards, measuring rows. Unfortunately,
*/
while (node && area_below > 0)
{
- gint new_height;
-
if (node->children)
{
GtkTreeIter parent = iter;
if (!node)
break;
- new_height = GTK_RBNODE_GET_HEIGHT (node);
-
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
- gint old_height = new_height;
-
_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);
size_changed = TRUE;
-
- area_below -= new_height - old_height;
- }
}
- area_below -= ROW_HEIGHT (tree_view, new_height);
+ area_below -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
}
gtk_tree_path_free (path);
/* We walk backwards */
while (area_above > 0)
{
- gint new_height;
-
_gtk_rbtree_prev_full (tree, node, &tree, &node);
if (! gtk_tree_path_prev (above_path) && node != NULL)
{
if (node == NULL)
break;
- new_height = GTK_RBNODE_GET_HEIGHT (node);
-
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
{
- gint old_height = new_height;
-
_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);
- size_changed = TRUE;
-
- area_above -= new_height - old_height;
- }
+ size_changed = TRUE;
}
- area_above -= ROW_HEIGHT (tree_view, new_height);
+ area_above -= ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node));
}
/* if we scrolled to a path, we need to set the dy here,
*/
if (tree_view->priv->scroll_to_path)
{
- gint dy;
-
- if (node != NULL)
- dy = _gtk_rbtree_node_find_offset (tree, node) - area_above;
- else
- dy = 0;
-
- gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
- gtk_tree_view_dy_to_top_row (tree_view);
+ gtk_tree_view_set_top_row (tree_view, above_path, -area_above);
+ gtk_tree_view_top_row_to_dy (tree_view);
need_redraw = TRUE;
}
{
gboolean retval;
- GDK_THREADS_ENTER ();
-
retval = do_validate_rows (tree_view, TRUE);
if (! retval && tree_view->priv->validate_rows_timer)
{
tree_view->priv->validate_rows_timer = 0;
}
- GDK_THREADS_LEAVE ();
-
return retval;
}
static gboolean
presize_handler_callback (gpointer data)
{
- GDK_THREADS_ENTER ();
-
do_presize_handler (GTK_TREE_VIEW (data));
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
if (! tree_view->priv->presize_handler_timer)
{
tree_view->priv->presize_handler_timer =
- g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
+ gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
}
if (! tree_view->priv->validate_rows_timer)
{
tree_view->priv->validate_rows_timer =
- g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
+ gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
}
}
static gboolean
scroll_sync_handler (GtkTreeView *tree_view)
{
-
- GDK_THREADS_ENTER ();
-
if (tree_view->priv->height <= tree_view->priv->vadjustment->page_size)
gtk_adjustment_set_value (GTK_ADJUSTMENT (tree_view->priv->vadjustment), 0);
else if (gtk_tree_row_reference_valid (tree_view->priv->top_row))
tree_view->priv->scroll_sync_timer = 0;
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
if (!tree_view->priv->scroll_sync_timer)
{
tree_view->priv->scroll_sync_timer =
- g_idle_add_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
+ gdk_threads_add_idle_full (GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC, (GSourceFunc) scroll_sync_handler, tree_view, NULL);
+ }
+}
+
+static void
+gtk_tree_view_set_top_row (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ gint offset)
+{
+ gtk_tree_row_reference_free (tree_view->priv->top_row);
+
+ if (!path)
+ {
+ tree_view->priv->top_row = NULL;
+ tree_view->priv->top_row_dy = 0;
+ }
+ else
+ {
+ tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
+ tree_view->priv->top_row_dy = offset;
}
}
static void
gtk_tree_view_dy_to_top_row (GtkTreeView *tree_view)
{
+ gint offset;
GtkTreePath *path;
GtkRBTree *tree;
GtkRBNode *node;
- gtk_tree_row_reference_free (tree_view->priv->top_row);
if (tree_view->priv->tree == NULL)
- tree = NULL;
+ {
+ gtk_tree_view_set_top_row (tree_view, NULL, 0);
+ }
else
- tree_view->priv->top_row_dy = _gtk_rbtree_find_offset (tree_view->priv->tree,
- tree_view->priv->dy,
- &tree, &node);
- if (tree == NULL)
{
- tree_view->priv->top_row = NULL;
- tree_view->priv->top_row_dy = 0;
- return;
+ offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
+ tree_view->priv->dy,
+ &tree, &node);
+
+ if (tree == NULL)
+ {
+ tree_view->priv->top_row = NULL;
+ tree_view->priv->top_row_dy = 0;
+ }
+ else
+ {
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ gtk_tree_view_set_top_row (tree_view, path, offset);
+ gtk_tree_path_free (path);
+ }
}
-
- path = _gtk_tree_view_find_path (tree_view, tree, node);
- tree_view->priv->top_row = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
- gtk_tree_path_free (path);
}
static void
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;
+ tree_view->priv->dy = MAX (0, tree_view->priv->dy);
+
gtk_adjustment_set_value (tree_view->priv->vadjustment,
(gdouble)tree_view->priv->dy);
}
}
#endif /* 0 */
+static void
+add_scroll_timeout (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->scroll_timeout == 0)
+ {
+ tree_view->priv->scroll_timeout =
+ gdk_threads_add_timeout (150, scroll_row_timeout, tree_view);
+ }
+}
+
static void
remove_scroll_timeout (GtkTreeView *tree_view)
{
GtkTreeViewDropPosition pos;
gboolean result = FALSE;
- GDK_THREADS_ENTER ();
-
gtk_tree_view_get_drag_dest_row (tree_view,
&dest_path,
&pos);
result = TRUE;
}
- GDK_THREADS_LEAVE ();
-
return result;
}
-static gint
+static gboolean
scroll_row_timeout (gpointer data)
{
GtkTreeView *tree_view = data;
- GDK_THREADS_ENTER ();
-
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;
}
static gboolean
set_destination_row (GtkTreeView *tree_view,
GdkDragContext *context,
+ /* coordinates relative to the widget */
gint x,
gint y,
GdkDragAction *suggested_action,
static gboolean
gtk_tree_view_drag_motion (GtkWidget *widget,
GdkDragContext *context,
+ /* coordinates relative to the widget */
gint x,
gint y,
guint time)
pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
{
tree_view->priv->open_dest_timeout =
- g_timeout_add (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
+ gdk_threads_add_timeout (AUTO_EXPAND_TIMEOUT, open_row_timeout, tree_view);
}
- else if (tree_view->priv->scroll_timeout == 0)
+ else
{
- tree_view->priv->scroll_timeout =
- g_timeout_add (150, scroll_row_timeout, tree_view);
+ add_scroll_timeout (tree_view);
}
if (target == gdk_atom_intern_static_string ("GTK_TREE_MODEL_ROW"))
static gboolean
gtk_tree_view_drag_drop (GtkWidget *widget,
GdkDragContext *context,
+ /* coordinates relative to the widget */
gint x,
gint y,
guint time)
static void
gtk_tree_view_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
+ /* coordinates relative to the widget */
gint x,
gint y,
GtkSelectionData *selection_data,
*/
static gboolean
gtk_tree_view_header_focus (GtkTreeView *tree_view,
- GtkDirectionType dir)
+ GtkDirectionType dir,
+ gboolean clamp_column_visible)
{
GtkWidget *focus_child;
}
- rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
- if (rtl) {
- GList *temp = first_column;
- first_column = last_column;
- last_column = temp;
- }
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
switch (dir)
{
if (GTK_TREE_VIEW_COLUMN (tmp_list->data)->button == focus_child)
break;
- if (tmp_list == first_column && dir == GTK_DIR_LEFT)
- {
- focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button;
- gtk_widget_grab_focus (focus_child);
- break;
- }
- else if (tmp_list == last_column && dir == GTK_DIR_RIGHT)
- {
- focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button;
- gtk_widget_grab_focus (focus_child);
+ if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
+ || (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
+ {
+ gtk_widget_error_bell (GTK_WIDGET (tree_view));
break;
}
{
GtkTreeViewColumn *column;
- if (dir == GTK_DIR_RIGHT)
+ if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
tmp_list = tmp_list->next;
else
tmp_list = tmp_list->prev;
break;
}
- /* If the following isn't true, then the view is smaller then the scrollpane.
- */
- if ((focus_child->allocation.x + focus_child->allocation.width) <=
- (tree_view->priv->hadjustment->upper))
- {
- /* Scroll to the button, if needed */
- if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
- (focus_child->allocation.x + focus_child->allocation.width))
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- focus_child->allocation.x + focus_child->allocation.width -
- tree_view->priv->hadjustment->page_size);
- else if (tree_view->priv->hadjustment->value > focus_child->allocation.x)
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- focus_child->allocation.x);
+ if (clamp_column_visible)
+ {
+ gtk_tree_view_clamp_column_visible (tree_view,
+ tree_view->priv->focus_column,
+ FALSE);
}
}
{
case GTK_DIR_LEFT:
case GTK_DIR_RIGHT:
- gtk_tree_view_header_focus (tree_view, direction);
+ gtk_tree_view_header_focus (tree_view, direction, TRUE);
return TRUE;
case GTK_DIR_TAB_BACKWARD:
case GTK_DIR_UP:
/* Case 2. We don't have focus at all. */
if (!GTK_WIDGET_HAS_FOCUS (container))
{
- if (!gtk_tree_view_header_focus (tree_view, direction))
+ if (!gtk_tree_view_header_focus (tree_view, direction, FALSE))
gtk_widget_grab_focus (widget);
return TRUE;
}
/* Case 3. We have focus already. */
if (direction == GTK_DIR_TAB_BACKWARD)
- return (gtk_tree_view_header_focus (tree_view, direction));
+ return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
else if (direction == GTK_DIR_TAB_FORWARD)
return FALSE;
{
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);
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);
static void
gtk_tree_view_put (GtkTreeView *tree_view,
GtkWidget *child_widget,
+ /* in tree coordinates */
gint x,
gint y,
gint width,
void
_gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
GtkWidget *widget,
+ /* in tree coordinates */
gint x,
gint y,
gint width,
GtkRBTree *tree;
GtkRBNode *node;
gboolean free_path = FALSE;
- gint vertical_separator;
GList *list;
GtkTreePath *cursor_path;
g_return_if_fail (path != NULL || iter != NULL);
- if (!GTK_WIDGET_REALIZED (tree_view))
- /* We can just ignore ::changed signals if we aren't realized, as we don't care about sizes
- */
- return;
-
if (tree_view->priv->cursor != NULL)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
else
if (cursor_path != NULL)
gtk_tree_path_free (cursor_path);
- gtk_widget_style_get (GTK_WIDGET (data), "vertical-separator", &vertical_separator, NULL);
-
if (path == NULL)
{
path = gtk_tree_model_get_path (model, iter);
&& tree_view->priv->fixed_height >= 0)
{
_gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
- gtk_tree_view_node_queue_redraw (tree_view, tree, node);
+ if (GTK_WIDGET_REALIZED (tree_view))
+ gtk_tree_view_node_queue_redraw (tree_view, tree, node);
}
else
{
}
done:
- if (!tree_view->priv->fixed_height_mode)
+ if (GTK_WIDGET_REALIZED (tree_view) && !tree_view->priv->fixed_height_mode)
install_presize_handler (tree_view);
if (free_path)
gtk_tree_path_free (path);
static void
gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view,
- GtkTreeViewColumn *column)
+ GtkTreeViewColumn *column,
+ gboolean focus_to_cell)
{
+ gint x, width;
+
if (column == NULL)
return;
- if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
- (column->button->allocation.x + column->button->allocation.width))
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- column->button->allocation.x + column->button->allocation.width -
- tree_view->priv->hadjustment->page_size);
- else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
- gtk_adjustment_set_value (tree_view->priv->hadjustment,
- column->button->allocation.x);
+
+ x = column->button->allocation.x;
+ width = column->button->allocation.width;
+
+ if (width > tree_view->priv->hadjustment->page_size)
+ {
+ /* The column is larger than the horizontal page size. If the
+ * column has cells which can be focussed individually, then we make
+ * sure the cell which gets focus is fully visible (if even the
+ * focus cell is bigger than the page size, we make sure the
+ * left-hand side of the cell is visible).
+ *
+ * If the column does not have those so-called special cells, we
+ * make sure the left-hand side of the column is visible.
+ */
+
+ if (focus_to_cell && gtk_tree_view_has_special_cell (tree_view))
+ {
+ GtkTreePath *cursor_path;
+ GdkRectangle background_area, cell_area, focus_area;
+
+ cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+
+ gtk_tree_view_get_cell_area (tree_view,
+ cursor_path, column, &cell_area);
+ gtk_tree_view_get_background_area (tree_view,
+ cursor_path, column,
+ &background_area);
+
+ gtk_tree_path_free (cursor_path);
+
+ _gtk_tree_view_column_get_focus_area (column,
+ &background_area,
+ &cell_area,
+ &focus_area);
+
+ x = focus_area.x;
+ width = focus_area.width;
+
+ if (width < tree_view->priv->hadjustment->page_size)
+ {
+ if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+ gtk_adjustment_set_value (tree_view->priv->hadjustment,
+ x + width - tree_view->priv->hadjustment->page_size);
+ else if (tree_view->priv->hadjustment->value > x)
+ gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+ }
+ }
+
+ gtk_adjustment_set_value (tree_view->priv->hadjustment,
+ CLAMP (x,
+ tree_view->priv->hadjustment->lower,
+ tree_view->priv->hadjustment->upper
+ - tree_view->priv->hadjustment->page_size));
+ }
+ else
+ {
+ if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) < (x + width))
+ gtk_adjustment_set_value (tree_view->priv->hadjustment,
+ x + width - tree_view->priv->hadjustment->page_size);
+ else if (tree_view->priv->hadjustment->value > x)
+ gtk_adjustment_set_value (tree_view->priv->hadjustment, x);
+ }
}
/* This function could be more efficient. I'll optimize it if profiling seems
gtk_tree_view_draw_arrow (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
+ /* in bin_window coordinates */
gint x,
gint y)
{
GtkRBTree *new_cursor_tree = NULL;
GtkRBNode *new_cursor_node = NULL;
GtkTreePath *cursor_path = NULL;
+ gboolean grab_focus = TRUE;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
return;
selection_count = gtk_tree_selection_count_selected_rows (tree_view->priv->selection);
- if (selection_count == 0 && !tree_view->priv->ctrl_pressed)
+ if (selection_count == 0
+ && tree_view->priv->selection->type != GTK_SELECTION_NONE
+ && !tree_view->priv->ctrl_pressed)
{
+ /* Don't move the cursor, but just select the current node */
new_cursor_tree = cursor_tree;
new_cursor_node = cursor_node;
}
else
{
gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
- }
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ if (!tree_view->priv->shift_pressed)
+ {
+ if (! gtk_widget_keynav_failed (GTK_WIDGET (tree_view),
+ count < 0 ?
+ GTK_DIR_UP : GTK_DIR_DOWN))
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (tree_view));
+
+ if (toplevel)
+ gtk_widget_child_focus (toplevel,
+ count < 0 ?
+ GTK_DIR_TAB_BACKWARD :
+ GTK_DIR_TAB_FORWARD);
+
+ grab_focus = FALSE;
+ }
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (tree_view));
+ }
+ }
+
+ if (grab_focus)
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
static void
{
GtkRBTree *cursor_tree = NULL;
GtkRBNode *cursor_node = NULL;
+ GtkTreePath *old_cursor_path = NULL;
GtkTreePath *cursor_path = NULL;
gint y;
gint window_y;
return;
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+ old_cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
else
/* This is sorta weird. Focus in should give us a cursor */
return;
gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical-separator", &vertical_separator, NULL);
- _gtk_tree_view_find_node (tree_view, cursor_path,
+ _gtk_tree_view_find_node (tree_view, old_cursor_path,
&cursor_tree, &cursor_node);
- gtk_tree_path_free (cursor_path);
-
if (cursor_tree == NULL)
- /* FIXME: we lost the cursor. Should we try to get one? */
- return;
+ {
+ /* FIXME: we lost the cursor. Should we try to get one? */
+ gtk_tree_path_free (old_cursor_path);
+ return;
+ }
g_return_if_fail (cursor_node != NULL);
y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node);
window_y = RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, y);
+ y += tree_view->priv->cursor_offset;
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;
- y -= _gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
+ tree_view->priv->cursor_offset =
+ _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+ &cursor_tree, &cursor_node);
+
+ if (tree_view->priv->cursor_offset >= BACKGROUND_HEIGHT (cursor_node))
+ {
+ _gtk_rbtree_next_full (cursor_tree, cursor_node,
+ &cursor_tree, &cursor_node);
+ tree_view->priv->cursor_offset -= BACKGROUND_HEIGHT (cursor_node);
+ }
+
+ y -= tree_view->priv->cursor_offset;
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, FALSE);
- gtk_tree_path_free (cursor_path);
y -= window_y;
gtk_tree_view_scroll_to_point (tree_view, -1, y);
+ _gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
+
+ if (!gtk_tree_path_compare (old_cursor_path, cursor_path))
+ gtk_widget_error_bell (GTK_WIDGET (tree_view));
+
+ gtk_tree_path_free (old_cursor_path);
+ gtk_tree_path_free (cursor_path);
}
static void
NULL);
g_signal_emit (tree_view, tree_view_signals[CURSOR_CHANGED], 0);
}
- gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (tree_view));
+ }
+
+ gtk_tree_view_clamp_column_visible (tree_view,
+ tree_view->priv->focus_column, TRUE);
}
static void
GtkRBTree *cursor_tree;
GtkRBNode *cursor_node;
GtkTreePath *path;
+ GtkTreePath *old_path;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
return;
g_return_if_fail (tree_view->priv->tree != NULL);
+ gtk_tree_view_get_cursor (tree_view, &old_path, NULL);
+
+ cursor_tree = tree_view->priv->tree;
+ cursor_node = cursor_tree->root;
+
if (count == -1)
{
- cursor_tree = tree_view->priv->tree;
- cursor_node = cursor_tree->root;
while (cursor_node && cursor_node->left != cursor_tree->nil)
cursor_node = cursor_node->left;
}
else
{
- cursor_tree = tree_view->priv->tree;
- cursor_node = cursor_tree->root;
do
{
while (cursor_node && cursor_node->right != cursor_tree->nil)
}
path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
- gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+
+ if (gtk_tree_path_compare (old_path, path))
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+ }
+ else
+ {
+ gtk_widget_error_bell (GTK_WIDGET (tree_view));
+ }
+
+ gtk_tree_path_free (old_path);
gtk_tree_path_free (path);
}
static gboolean
gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
{
- GDK_THREADS_ENTER ();
-
gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
tree_view->priv->typeselect_flush_timeout = 0;
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
}
tree_view->priv->typeselect_flush_timeout =
- g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+ gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
(GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
tree_view);
}
gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
- /* update our dy and top_row */
- tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
- gtk_tree_view_dy_to_top_row (tree_view);
+ if (tree_view->priv->dy != (int) tree_view->priv->vadjustment->value)
+ {
+ /* update our dy and top_row */
+ tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
+ gtk_tree_view_dy_to_top_row (tree_view);
+ }
}
}
*
* Scrolls the tree view such that the top-left corner of the visible
* area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
- * in tree window coordinates. The @tree_view must be realized before
+ * in tree coordinates. The @tree_view must be realized before
* this function is called. If it isn't, you probably want to be
* using gtk_tree_view_scroll_to_cell().
*
gint dest_x, dest_y;
gtk_tree_view_get_background_area (tree_view, path, column, &cell_rect);
- gtk_tree_view_tree_window_to_tree_coords (tree_view, cell_rect.x, cell_rect.y, &(cell_rect.x), &(cell_rect.y));
gtk_tree_view_get_visible_rect (tree_view, &vis_rect);
+ cell_rect.y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, cell_rect.y);
+
dest_x = vis_rect.x;
dest_y = vis_rect.y;
static gboolean
expand_collapse_timeout (gpointer data)
{
- gboolean retval;
-
- GDK_THREADS_ENTER ();
-
- retval = do_expand_collapse (data);
-
- GDK_THREADS_LEAVE ();
-
- return retval;
+ return do_expand_collapse (data);
}
static gboolean
if (animate)
{
- tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
tree_view->priv->expanded_collapsed_node = node;
tree_view->priv->expanded_collapsed_tree = tree;
install_presize_handler (tree_view);
g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
- if (open_all)
+ if (open_all && node->children)
{
_gtk_rbtree_traverse (node->children,
node->children->root,
if (animate)
{
- tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expand_collapse_timeout = gdk_threads_add_timeout (50, expand_collapse_timeout, tree_view);
tree_view->priv->expanded_collapsed_node = node;
tree_view->priv->expanded_collapsed_tree = tree;
/**
* gtk_tree_view_get_path_at_pos:
* @tree_view: A #GtkTreeView.
- * @x: The x position to be identified.
- * @y: The y position to be identified.
+ * @x: The x position to be identified (relative to bin_window).
+ * @y: The y position to be identified (relative to bin_window).
* @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
* @column: A pointer to a #GtkTreeViewColumn pointer to be filled in, or %NULL
* @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
* @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
*
- * Finds the path at the point (@x, @y), relative to widget coordinates. That
- * is, @x and @y are relative to an events coordinates. @x and @y must come
- * from an event on the @tree_view only where <literal>event->window ==
- * gtk_tree_view_get_bin (<!-- -->)</literal>. It is primarily for things
- * like popup menus. If @path is non-%NULL, then it will be filled with the
- * #GtkTreePath at that point. This path should be freed with gtk_tree_path_free().
- * If @column is non-%NULL, then it will be filled with the column at that point.
- * @cell_x and @cell_y return the coordinates relative to the cell background
- * (i.e. the @background_area passed to gtk_cell_renderer_render()). This
- * function is only meaningful if @tree_view is realized.
+ * Finds the path at the point (@x, @y), relative to bin_window coordinates
+ * (please see gtk_tree_view_get_bin_window()).
+ * That is, @x and @y are relative to an events coordinates. @x and @y must
+ * come from an event on the @tree_view only where <literal>event->window ==
+ * gtk_tree_view_get_bin_window (<!-- -->)</literal>. It is primarily for
+ * things like popup menus. If @path is non-%NULL, then it will be filled
+ * with the #GtkTreePath at that point. This path should be freed with
+ * gtk_tree_path_free(). If @column is non-%NULL, then it will be filled
+ * with the column at that point. @cell_x and @cell_y return the coordinates
+ * relative to the cell background (i.e. the @background_area passed to
+ * gtk_cell_renderer_render()). This function is only meaningful if
+ * @tree_view is realized.
+ *
+ * For converting widget coordinates (eg. the ones you get from
+ * GtkWidget::query-tooltip), please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
*
* Return value: %TRUE if a row exists at that coordinate.
**/
* @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordinates
* @rect: rectangle to fill with cell rect
*
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
* row specified by @path and the column specified by @column. If @path is
* %NULL, or points to a path not currently displayed, the @y and @height fields
* of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
* @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
* @rect: rectangle to fill with cell background rect
*
- * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * Fills the bounding rectangle in bin_window coordinates for the cell at the
* row specified by @path and the column specified by @column. If @path is
* %NULL, or points to a node not found in the tree, the @y and @height fields of
* the rectangle will be filled with 0. If @column is %NULL, the @x and @width
* fields will be filled with 0. The returned rectangle is equivalent to the
* @background_area passed to gtk_cell_renderer_render(). These background
- * areas tile to cover the entire tree window (except for the area used for
- * header buttons). Contrast with the @cell_area, returned by
- * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
- * surrounding borders and the tree expander area.
+ * areas tile to cover the entire bin window. Contrast with the @cell_area,
+ * returned by gtk_tree_view_get_cell_area(), which returns only the cell
+ * itself, excluding surrounding borders and the tree expander area.
*
**/
void
* @visible_rect: rectangle to fill
*
* Fills @visible_rect with the currently-visible region of the
- * buffer, in tree coordinates. Convert to widget coordinates with
- * gtk_tree_view_tree_to_widget_coords(). Tree coordinates start at
- * 0,0 for row 0 of the tree, and cover the entire scrollable area of
- * the tree.
+ * buffer, in tree coordinates. Convert to bin_window coordinates with
+ * gtk_tree_view_convert_tree_to_bin_window_coords().
+ * Tree coordinates start at 0,0 for row 0 of the tree, and cover the entire
+ * scrollable area of the tree.
**/
void
gtk_tree_view_get_visible_rect (GtkTreeView *tree_view,
/**
* gtk_tree_view_widget_to_tree_coords:
* @tree_view: a #GtkTreeView
- * @wx: widget X coordinate
- * @wy: widget Y coordinate
+ * @wx: X coordinate relative to bin_window
+ * @wy: Y coordinate relative to bin_window
* @tx: return location for tree X coordinate
* @ty: return location for tree Y coordinate
*
- * Converts widget coordinates to coordinates for the
- * tree window (the full scrollable area of the tree).
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect. For converting coordinates relative to the widget to
+ * bin_window coordinates, please see
+ * gtk_tree_view_convert_widget_to_bin_window_coords().
*
**/
void
*ty = wy + tree_view->priv->dy;
}
-static void
-gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
- gint wx,
- gint wy,
- gint *tx,
- gint *ty)
-{
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
- if (tx)
- *tx = wx;
- if (ty)
- *ty = wy + tree_view->priv->dy;
-}
-
/**
* gtk_tree_view_tree_to_widget_coords:
* @tree_view: a #GtkTreeView
* @tx: tree X coordinate
* @ty: tree Y coordinate
- * @wx: return location for widget X coordinate
- * @wy: return location for widget Y coordinate
+ * @wx: return location for X coordinate relative to bin_window
+ * @wy: return location for Y coordinate relative to bin_window
*
* Converts tree coordinates (coordinates in full scrollable area of the tree)
- * to widget coordinates.
+ * to bin_window coordinates.
+ *
+ * Deprecated: 2.12: Due to historial reasons the name of this function is
+ * incorrect. For converting bin_window coordinates to coordinates relative
+ * to bin_window, please see
+ * gtk_tree_view_convert_bin_window_to_widget_coords().
*
**/
void
*wy = ty - tree_view->priv->dy;
}
+
+/**
+ * gtk_tree_view_convert_widget_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_tree_coords (GtkTreeView *tree_view,
+ gint wx,
+ gint wy,
+ gint *tx,
+ gint *ty)
+{
+ gint x, y;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ gtk_tree_view_convert_widget_to_bin_window_coords (tree_view,
+ wx, wy,
+ &x, &y);
+ gtk_tree_view_convert_bin_window_to_tree_coords (tree_view,
+ x, y,
+ tx, ty);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: X coordinate relative to the tree
+ * @ty: Y coordinate relative to the tree
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to widget coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_widget_coords (GtkTreeView *tree_view,
+ gint tx,
+ gint ty,
+ gint *wx,
+ gint *wy)
+{
+ gint x, y;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ gtk_tree_view_convert_tree_to_bin_window_coords (tree_view,
+ tx, ty,
+ &x, &y);
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+ x, y,
+ wx, wy);
+}
+
+/**
+ * gtk_tree_view_convert_widget_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @wx: X coordinate relative to the widget
+ * @wy: Y coordinate relative to the widget
+ * @bx: return location for bin_window X coordinate
+ * @by: return location for bin_window Y coordinate
+ *
+ * Converts widget coordinates to coordinates for the bin_window
+ * (see gtk_tree_view_get_bin_window()).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_widget_to_bin_window_coords (GtkTreeView *tree_view,
+ gint wx,
+ gint wy,
+ gint *bx,
+ gint *by)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (bx)
+ *bx = wx + tree_view->priv->hadjustment->value;
+ if (by)
+ *by = wy - TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_widget_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: bin_window X coordinate
+ * @by: bin_window Y coordinate
+ * @wx: return location for widget X coordinate
+ * @wy: return location for widget Y coordinate
+ *
+ * Converts bin_window coordinates (see gtk_tree_view_get_bin_window())
+ * to widget relative coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_widget_coords (GtkTreeView *tree_view,
+ gint bx,
+ gint by,
+ gint *wx,
+ gint *wy)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (wx)
+ *wx = bx - tree_view->priv->hadjustment->value;
+ if (wy)
+ *wy = by + TREE_VIEW_HEADER_HEIGHT (tree_view);
+}
+
+/**
+ * gtk_tree_view_convert_tree_to_bin_window_coords:
+ * @tree_view: a #GtkTreeView
+ * @tx: tree X coordinate
+ * @ty: tree Y coordinate
+ * @bx: return location for X coordinate relative to bin_window
+ * @by: return location for Y coordinate relative to bin_window
+ *
+ * Converts tree coordinates (coordinates in full scrollable area of the tree)
+ * to bin_window coordinates.
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_tree_to_bin_window_coords (GtkTreeView *tree_view,
+ gint tx,
+ gint ty,
+ gint *bx,
+ gint *by)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (bx)
+ *bx = tx;
+ if (by)
+ *by = ty - tree_view->priv->dy;
+}
+
+/**
+ * gtk_tree_view_convert_bin_window_to_tree_coords:
+ * @tree_view: a #GtkTreeView
+ * @bx: X coordinate relative to bin_window
+ * @by: Y coordinate relative to bin_window
+ * @tx: return location for tree X coordinate
+ * @ty: return location for tree Y coordinate
+ *
+ * Converts bin_window coordinates to coordinates for the
+ * tree (the full scrollable area of the tree).
+ *
+ * Since: 2.12
+ **/
+void
+gtk_tree_view_convert_bin_window_to_tree_coords (GtkTreeView *tree_view,
+ gint bx,
+ gint by,
+ gint *tx,
+ gint *ty)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (tx)
+ *tx = bx;
+ if (ty)
+ *ty = by + tree_view->priv->dy;
+}
+
+
+
/**
* gtk_tree_view_get_visible_range:
* @tree_view: A #GtkTreeView
* @path: Return location for the path of the highlighted row, or %NULL.
* @pos: Return location for the drop position, or %NULL
*
- * Determines the destination row for a given position.
+ * Determines the destination row for a given position. @drag_x and
+ * @drag_y are expected to be in widget coordinates.
*
* Return value: whether there is a row at the given position.
**/
GtkTreeViewDropPosition *pos)
{
gint cell_y;
+ gint bin_x, bin_y;
gdouble offset_into_row;
gdouble third;
GdkRectangle cell;
* in the bottom third, drop after that row; if in the middle,
* and the row has children, drop into the row.
*/
+ gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, drag_x, drag_y,
+ &bin_x, &bin_y);
if (!gtk_tree_view_get_path_at_pos (tree_view,
- drag_x,
- drag_y - TREE_VIEW_HEADER_HEIGHT (tree_view),
+ bin_x,
+ bin_y,
&tmp_path,
&column,
NULL,
tree_view->priv->typeselect_flush_timeout = 0;
}
- /* send focus-in event */
- send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
- gtk_widget_hide (search_dialog);
- gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+ if (GTK_WIDGET_VISIBLE (search_dialog))
+ {
+ /* send focus-in event */
+ send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
+ gtk_widget_hide (search_dialog);
+ gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
+ send_focus_change (GTK_WIDGET (tree_view), TRUE);
+ }
}
static void
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
- g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+ gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
(GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
tree_view);
}
{
GtkTreeView *tree_view = (GtkTreeView *)data;
- GDK_THREADS_ENTER ();
-
tree_view->priv->disable_popdown = 0;
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
gtk_tree_view_search_enable_popdown (GtkWidget *widget,
gpointer data)
{
- g_timeout_add (200, gtk_tree_view_real_search_enable_popdown, data);
+ gdk_threads_add_timeout_full (G_PRIORITY_HIGH, 200, gtk_tree_view_real_search_enable_popdown, g_object_ref (data), g_object_unref);
}
static gboolean
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
- g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+ gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
(GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
tree_view);
}
/* select previous matching iter */
if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
{
- gtk_tree_view_search_move (widget, tree_view, TRUE);
+ if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
+ gtk_widget_error_bell (widget);
+
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);
+ if (!gtk_tree_view_search_move (widget, tree_view, TRUE))
+ gtk_widget_error_bell (widget);
+
retval = TRUE;
}
/* select next matching iter */
if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
{
- gtk_tree_view_search_move (widget, tree_view, FALSE);
+ if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
+ gtk_widget_error_bell (widget);
+
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);
+ if (!gtk_tree_view_search_move (widget, tree_view, FALSE))
+ gtk_widget_error_bell (widget);
+
retval = TRUE;
}
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
- g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+ gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
(GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
tree_view);
}
return retval;
}
-static void
+/* this function returns FALSE if there is a search string but
+ * nothing was found, and TRUE otherwise.
+ */
+static gboolean
gtk_tree_view_search_move (GtkWidget *window,
GtkTreeView *tree_view,
gboolean up)
text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
- g_return_if_fail (text != NULL);
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ len = strlen (text);
if (up && tree_view->priv->selected_iter == 1)
- return;
+ return strlen (text) < 1;
len = strlen (text);
if (len < 1)
- return;
+ return TRUE;
model = gtk_tree_view_get_model (tree_view);
selection = gtk_tree_view_get_selection (tree_view);
/* search */
gtk_tree_selection_unselect_all (selection);
if (!gtk_tree_model_get_iter_first (model, &iter))
- return;
+ return TRUE;
ret = gtk_tree_view_search_iter (model, selection, &iter, text,
&count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
{
/* found */
tree_view->priv->selected_iter += up?(-1):(1);
+ return TRUE;
}
else
{
gtk_tree_view_search_iter (model, selection,
&iter, text,
&count, tree_view->priv->selected_iter);
+ return FALSE;
}
}
/* search */
gtk_tree_selection_unselect_all (selection);
if (tree_view->priv->typeselect_flush_timeout
- && tree_view->priv->search_custom_entry_set)
+ && !tree_view->priv->search_custom_entry_set)
{
g_source_remove (tree_view->priv->typeselect_flush_timeout);
tree_view->priv->typeselect_flush_timeout =
- g_timeout_add (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
+ gdk_threads_add_timeout (GTK_TREE_VIEW_SEARCH_DIALOG_TIMEOUT,
(GSourceFunc) gtk_tree_view_search_entry_flush_timeout,
tree_view);
}
return tree_view->priv->rubber_banding_enable;
}
+/**
+ * gtk_tree_view_is_rubber_banding_active:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns whether a rubber banding operation is currently being done
+ * in @tree_view.
+ *
+ * Return value: %TRUE if a rubber banding operation is currently being
+ * done in @tree_view.
+ *
+ * Since: 2.12
+ **/
+gboolean
+gtk_tree_view_is_rubber_banding_active (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ if (tree_view->priv->rubber_banding_enable
+ && tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
+ return TRUE;
+
+ return FALSE;
+}
+
/**
* gtk_tree_view_get_row_separator_func:
* @tree_view: a #GtkTreeView
tree_view->priv->in_grab = !was_grabbed;
if (!was_grabbed)
- tree_view->priv->pressed_button = -1;
+ {
+ tree_view->priv->pressed_button = -1;
+
+ if (tree_view->priv->rubber_band_status)
+ gtk_tree_view_stop_rubber_band (tree_view);
+ }
}
static void
}
}
+
+/**
+ * gtk_tree_view_set_show_expanders:
+ * @tree_view: a #GtkTreeView
+ * @enabled: %TRUE to enable expander drawing, %FALSE otherwise.
+ *
+ * Sets whether to draw and enable expanders and indent child rows in
+ * @tree_view. When disabled there will be no expanders visible in trees
+ * and there will be no way to expand and collapse rows by default. Also
+ * note that hiding the expanders will disable the default indentation. You
+ * can set a custom indentation in this case using
+ * gtk_tree_view_set_level_indentation().
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_show_expanders (GtkTreeView *tree_view,
+ gboolean enabled)
+{
+ gboolean was_enabled;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ enabled = enabled != FALSE;
+ was_enabled = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+
+ if (enabled)
+ 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);
+
+ if (was_enabled != was_enabled)
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_show_expanders:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns whether or not expanders are drawn in @tree_view.
+ *
+ * Return value: %TRUE if expanders are drawn in @tree_view, %FALSE
+ * otherwise.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_tree_view_get_show_expanders (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+
+ return GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_SHOW_EXPANDERS);
+}
+
+/**
+ * gtk_tree_view_set_level_indentation:
+ * @tree_view: a #GtkTreeView
+ * @indentation: the amount, in pixels, of extra indentation in @tree_view.
+ *
+ * Sets the amount of extra indentation for child levels to use in @tree_view
+ * in addition to the default indentation. The value should be specified in
+ * pixels, a value of 0 disables this feature and in this case only the default
+ * indentation will be used.
+ * This does not have any visible effects for lists.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_level_indentation (GtkTreeView *tree_view,
+ gint indentation)
+{
+ tree_view->priv->level_indentation = indentation;
+
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/**
+ * gtk_tree_view_get_level_indentation:
+ * @tree_view: a #GtkTreeView.
+ *
+ * Returns the amount, in pixels, of extra indentation for child levels
+ * in @tree_view.
+ *
+ * Return value: the amount of extra indentation for child levels in
+ * @tree_view. A return value of 0 means that this feature is disabled.
+ *
+ * Since: 2.12
+ */
+gint
+gtk_tree_view_get_level_indentation (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return tree_view->priv->level_indentation;
+}
+
+/**
+ * gtk_tree_view_set_tooltip_row:
+ * @tree_view: a #GtkTreeView
+ * @tooltip: a #GtkTooltip
+ * @path: a #GtkTreePath
+ *
+ * Sets the tip area of @tooltip to be the area covered by the row at @path.
+ * See also gtk_tooltip_set_tip_area().
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_row (GtkTreeView *tree_view,
+ GtkTooltip *tooltip,
+ GtkTreePath *path)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+ gtk_tree_view_set_tooltip_cell (tree_view, tooltip, path, NULL, NULL);
+}
+
+/**
+ * gtk_tree_view_set_tooltip_cell:
+ * @tree_view: a #GtkTreeView
+ * @tooltip: a #GtkTooltip
+ * @path: a #GtkTreePath or %NULL
+ * @column: a #GtkTreeViewColumn or %NULL
+ * @cell: a #GtkCellRenderer or %NULL
+ *
+ * Sets the tip area of @tooltip to the area @path, @column and @cell have
+ * in common. For example if @path is %NULL and @column is set, the tip
+ * area will be set to the full area covered by @column. See also
+ * gtk_tooltip_set_tip_area().
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_cell (GtkTreeView *tree_view,
+ GtkTooltip *tooltip,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ GtkCellRenderer *cell)
+{
+ GdkRectangle rect;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_TOOLTIP (tooltip));
+
+ if (column)
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (column));
+
+ if (cell)
+ g_return_if_fail (GTK_IS_CELL_RENDERER (cell));
+
+ /* Determine x values. */
+ if (column && cell)
+ {
+ GdkRectangle tmp;
+ gint start, width;
+
+ gtk_tree_view_get_cell_area (tree_view, NULL, column, &tmp);
+ gtk_tree_view_column_cell_get_position (column, cell, &start, &width);
+
+ /* FIXME: a need a path here to correctly correct for indent */
+
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+ tmp.x + start, 0,
+ &rect.x, NULL);
+ rect.width = width;
+ }
+ else if (column)
+ {
+ GdkRectangle tmp;
+
+ gtk_tree_view_get_background_area (tree_view, NULL, column, &tmp);
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+ tmp.x, 0,
+ &rect.x, NULL);
+ rect.width = tmp.width;
+ }
+ else
+ {
+ rect.x = 0;
+ rect.width = GTK_WIDGET (tree_view)->allocation.width;
+ }
+
+ /* Determine y values. */
+ if (path)
+ {
+ GdkRectangle tmp;
+
+ gtk_tree_view_get_background_area (tree_view, path, NULL, &tmp);
+ gtk_tree_view_convert_bin_window_to_widget_coords (tree_view,
+ 0, tmp.y,
+ NULL, &rect.y);
+ rect.height = tmp.height;
+ }
+ else
+ {
+ rect.y = 0;
+ rect.height = tree_view->priv->vadjustment->page_size;
+ }
+
+ gtk_tooltip_set_tip_area (tooltip, &rect);
+}
+
+/**
+ * gtk_tree_view_get_tooltip_context:
+ * @tree_view: a #GtkTreeView
+ * @x: the x coordinate (relative to widget coordinates)
+ * @y: the y coordinate (relative to widget coordinates)
+ * @keyboard_tip: whether this is a keyboard tooltip or not
+ * @model: a pointer to receive a #GtkTreeModel or %NULL
+ * @path: a pointer to receive a #GtkTreePath or %NULL
+ * @iter: a pointer to receive a #GtkTreeIter or %NULL
+ *
+ * This function is supposed to be used in a #GtkWidget::query-tooltip
+ * signal handler for #GtkTreeView. The @x, @y and @keyboard_tip values
+ * which are received in the signal handler, should be passed to this
+ * function without modification.
+ *
+ * The return value indicates whether there is a tree view row at the given
+ * coordinates (%TRUE) or not (%FALSE) for mouse tooltips. For keyboard
+ * tooltips the row returned will be the cursor row. When %TRUE, then any of
+ * @model, @path and @iter which have been provided will be set to point to
+ * that row and the corresponding model. @x and @y will always be converted
+ * to be relative to @tree_view's bin_window if @keyboard_tooltip is %FALSE.
+ *
+ * Return value: whether or not the given tooltip context points to a row.
+ *
+ * Since: 2.12
+ */
+gboolean
+gtk_tree_view_get_tooltip_context (GtkTreeView *tree_view,
+ gint *x,
+ gint *y,
+ gboolean keyboard_tip,
+ GtkTreeModel **model,
+ GtkTreePath **path,
+ GtkTreeIter *iter)
+{
+ GtkTreePath *tmppath = NULL;
+
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
+ g_return_val_if_fail (x != NULL, FALSE);
+ g_return_val_if_fail (y != NULL, FALSE);
+
+ if (keyboard_tip)
+ {
+ gtk_tree_view_get_cursor (tree_view, &tmppath, NULL);
+
+ if (!tmppath)
+ return FALSE;
+ }
+ else
+ {
+ gtk_tree_view_convert_widget_to_bin_window_coords (tree_view, *x, *y,
+ x, y);
+
+ if (!gtk_tree_view_get_path_at_pos (tree_view, *x, *y,
+ &tmppath, NULL, NULL, NULL))
+ return FALSE;
+ }
+
+ if (model)
+ *model = gtk_tree_view_get_model (tree_view);
+
+ if (iter)
+ gtk_tree_model_get_iter (gtk_tree_view_get_model (tree_view),
+ iter, tmppath);
+
+ if (path)
+ *path = tmppath;
+ else
+ gtk_tree_path_free (tmppath);
+
+ return TRUE;
+}
+
+static gboolean
+gtk_tree_view_set_tooltip_query_cb (GtkWidget *widget,
+ gint x,
+ gint y,
+ gboolean keyboard_tip,
+ GtkTooltip *tooltip,
+ gpointer data)
+{
+ gchar *str;
+ GtkTreeIter iter;
+ GtkTreePath *path;
+ GtkTreeModel *model;
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+
+ if (!gtk_tree_view_get_tooltip_context (GTK_TREE_VIEW (widget),
+ &x, &y,
+ keyboard_tip,
+ &model, &path, &iter))
+ return FALSE;
+
+ gtk_tree_model_get (model, &iter, tree_view->priv->tooltip_column, &str, -1);
+
+ if (!str)
+ {
+ gtk_tree_path_free (path);
+ return FALSE;
+ }
+
+ gtk_tooltip_set_markup (tooltip, str);
+ gtk_tree_view_set_tooltip_row (tree_view, tooltip, path);
+
+ gtk_tree_path_free (path);
+ g_free (str);
+
+ return TRUE;
+}
+
+/**
+ * gtk_tree_view_set_tooltip_column:
+ * @tree_view: a #GtkTreeView
+ * @column: an integer, which is a valid column number for @tree_view's model
+ *
+ * If you only plan to have simple (text-only) tooltips on full rows, you
+ * can use this function to have #GtkTreeView handle these automatically
+ * for you. @column should be set to the column in @tree_view's model
+ * containing the tooltip texts, or -1 to disable this feature.
+ *
+ * When enabled, #GtkWidget::has-tooltip will be set to %TRUE and
+ * @tree_view will connect a #GtkWidget::query-tooltip signal handler.
+ *
+ * Since: 2.12
+ */
+void
+gtk_tree_view_set_tooltip_column (GtkTreeView *tree_view,
+ gint column)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (column == tree_view->priv->tooltip_column)
+ return;
+
+ if (column == -1)
+ {
+ g_signal_handlers_disconnect_by_func (tree_view,
+ gtk_tree_view_set_tooltip_query_cb,
+ NULL);
+ gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), FALSE);
+ }
+ else
+ {
+ if (tree_view->priv->tooltip_column == -1)
+ {
+ g_signal_connect (tree_view, "query-tooltip",
+ G_CALLBACK (gtk_tree_view_set_tooltip_query_cb), NULL);
+ gtk_widget_set_has_tooltip (GTK_WIDGET (tree_view), TRUE);
+ }
+ }
+
+ tree_view->priv->tooltip_column = column;
+ g_object_notify (G_OBJECT (tree_view), "tooltip-column");
+}
+
+/**
+ * gtk_tree_view_get_tooltip_column:
+ * @tree_view: a #GtkTreeView
+ *
+ * Returns the column of @tree_view's model which is being used for
+ * displaying tooltips on @tree_view's rows.
+ *
+ * Return value: the index of the tooltip column that is currently being
+ * used, or -1 if this is disabled.
+ *
+ * Since: 2.12
+ */
+gint
+gtk_tree_view_get_tooltip_column (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
+
+ return tree_view->priv->tooltip_column;
+}
+
#define __GTK_TREE_VIEW_C__
#include "gtkaliasdef.c"