*/
+#include <config.h>
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include "gtkentry.h"
#include "gtktreemodelsort.h"
-#define GTK_TREE_VIEW_SEARCH_DIALOG_KEY "gtk-tree-view-search-dialog"
#define GTK_TREE_VIEW_PRIORITY_VALIDATE (GDK_PRIORITY_REDRAW + 5)
#define GTK_TREE_VIEW_PRIORITY_SCROLL_SYNC (GTK_TREE_VIEW_PRIORITY_VALIDATE + 2)
#define GTK_TREE_VIEW_NUM_ROWS_PER_IDLE 500
PROP_REORDERABLE,
PROP_RULES_HINT,
PROP_ENABLE_SEARCH,
- PROP_SEARCH_COLUMN
+ PROP_SEARCH_COLUMN,
+ PROP_FIXED_HEIGHT_MODE
};
static void gtk_tree_view_class_init (GtkTreeViewClass *klass);
GdkEventButton *event);
static gboolean gtk_tree_view_button_release (GtkWidget *widget,
GdkEventButton *event);
+#if 0
+static gboolean gtk_tree_view_configure (GtkWidget *widget,
+ GdkEventConfigure *event);
+#endif
+
static void gtk_tree_view_set_focus_child (GtkContainer *container,
GtkWidget *child);
static gint gtk_tree_view_focus_out (GtkWidget *widget,
static gboolean gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
GtkMovementStep step,
gint count);
-static void gtk_tree_view_real_select_all (GtkTreeView *tree_view);
-static void gtk_tree_view_real_unselect_all (GtkTreeView *tree_view);
-static void gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
+static gboolean gtk_tree_view_real_select_all (GtkTreeView *tree_view);
+static gboolean gtk_tree_view_real_unselect_all (GtkTreeView *tree_view);
+static gboolean gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
gboolean start_editing);
-static void gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view);
-static void gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
- gboolean logical,
- gboolean expand,
- gboolean open_all);
-static void gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view);
+static gboolean gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view);
+static gboolean gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
+ gboolean logical,
+ gboolean expand,
+ gboolean open_all);
+static gboolean gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view);
static void gtk_tree_view_row_changed (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gboolean clear_and_select,
gboolean clamp_node);
static gboolean gtk_tree_view_has_special_cell (GtkTreeView *tree_view);
+static void column_sizing_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer data);
+static void gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
+ gboolean enable);
+
+static gboolean expand_collapse_timeout (gpointer data);
+static gboolean do_expand_collapse (GtkTreeView *tree_view);
/* interactive search */
-static void gtk_tree_view_search_dialog_destroy (GtkWidget *search_dialog,
+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);
guint flags);
static void gtk_tree_view_stop_editing (GtkTreeView *tree_view,
gboolean cancel_editing);
-static void gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view);
+static gboolean gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view);
static GtkTreeViewColumn *gtk_tree_view_get_drop_column (GtkTreeView *tree_view,
GtkTreeViewColumn *column,
gint drop_position);
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->configure_event = gtk_tree_view_configure;*/
widget_class->motion_notify_event = gtk_tree_view_motion;
widget_class->expose_event = gtk_tree_view_expose;
widget_class->key_press_event = gtk_tree_view_key_press;
g_object_class_install_property (o_class,
PROP_MODEL,
g_param_spec_object ("model",
- _("TreeView Model"),
- _("The model for the tree view"),
+ P_("TreeView Model"),
+ P_("The model for the tree view"),
GTK_TYPE_TREE_MODEL,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_HADJUSTMENT,
g_param_spec_object ("hadjustment",
- _("Horizontal Adjustment"),
- _("Horizontal Adjustment for the widget"),
+ P_("Horizontal Adjustment"),
+ P_("Horizontal Adjustment for the widget"),
GTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_VADJUSTMENT,
g_param_spec_object ("vadjustment",
- _("Vertical Adjustment"),
- _("Vertical Adjustment for the widget"),
+ P_("Vertical Adjustment"),
+ P_("Vertical Adjustment for the widget"),
GTK_TYPE_ADJUSTMENT,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_HEADERS_VISIBLE,
g_param_spec_boolean ("headers_visible",
- _("Visible"),
- _("Show the column header buttons"),
+ P_("Visible"),
+ P_("Show the column header buttons"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_HEADERS_CLICKABLE,
g_param_spec_boolean ("headers_clickable",
- _("Headers Clickable"),
- _("Column headers respond to click events"),
+ P_("Headers Clickable"),
+ P_("Column headers respond to click events"),
FALSE,
G_PARAM_WRITABLE));
g_object_class_install_property (o_class,
PROP_EXPANDER_COLUMN,
g_param_spec_object ("expander_column",
- _("Expander Column"),
- _("Set the column for the expander column"),
+ P_("Expander Column"),
+ P_("Set the column for the expander column"),
GTK_TYPE_TREE_VIEW_COLUMN,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_REORDERABLE,
g_param_spec_boolean ("reorderable",
- _("Reorderable"),
- _("View is reorderable"),
+ P_("Reorderable"),
+ P_("View is reorderable"),
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_RULES_HINT,
g_param_spec_boolean ("rules_hint",
- _("Rules Hint"),
- _("Set a hint to the theme engine to draw rows in alternating colors"),
+ P_("Rules Hint"),
+ P_("Set a hint to the theme engine to draw rows in alternating colors"),
FALSE,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_ENABLE_SEARCH,
g_param_spec_boolean ("enable_search",
- _("Enable Search"),
- _("View allows user to search through columns interactively"),
+ P_("Enable Search"),
+ P_("View allows user to search through columns interactively"),
TRUE,
G_PARAM_READWRITE));
g_object_class_install_property (o_class,
PROP_SEARCH_COLUMN,
g_param_spec_int ("search_column",
- _("Search Column"),
- _("Model column to search through when searching through code"),
+ P_("Search Column"),
+ P_("Model column to search through when searching through code"),
-1,
G_MAXINT,
0,
G_PARAM_READWRITE));
+ g_object_class_install_property (o_class,
+ PROP_FIXED_HEIGHT_MODE,
+ g_param_spec_boolean ("fixed_height_mode",
+ P_("Fixed Height Mode"),
+ P_("Speeds up GtkTreeView by assuming that all rows have the same height"),
+ FALSE,
+ G_PARAM_READWRITE));
+
/* Style properties */
#define _TREE_VIEW_EXPANDER_SIZE 10
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("expander_size",
- _("Expander Size"),
- _("Size of the expander arrow"),
+ P_("Expander Size"),
+ P_("Size of the expander arrow"),
0,
G_MAXINT,
_TREE_VIEW_EXPANDER_SIZE,
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("vertical_separator",
- _("Vertical Separator Width"),
- _("Vertical space between cells. Must be an even number"),
+ P_("Vertical Separator Width"),
+ P_("Vertical space between cells. Must be an even number"),
0,
G_MAXINT,
_TREE_VIEW_VERTICAL_SEPARATOR,
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("horizontal_separator",
- _("Horizontal Separator Width"),
- _("Horizontal space between cells. Must be an even number"),
+ P_("Horizontal Separator Width"),
+ P_("Horizontal space between cells. Must be an even number"),
0,
G_MAXINT,
_TREE_VIEW_HORIZONTAL_SEPARATOR,
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boolean ("allow_rules",
- _("Allow Rules"),
- _("Allow drawing of alternating color rows"),
+ P_("Allow Rules"),
+ P_("Allow drawing of alternating color rows"),
TRUE,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boolean ("indent_expanders",
- _("Indent Expanders"),
- _("Make the expanders indented"),
+ P_("Indent Expanders"),
+ P_("Make the expanders indented"),
TRUE,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boxed ("even_row_color",
- _("Even Row Color"),
- _("Color to use for even rows"),
+ P_("Even Row Color"),
+ P_("Color to use for even rows"),
GDK_TYPE_COLOR,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boxed ("odd_row_color",
- _("Odd Row Color"),
- _("Color to use for odd rows"),
+ P_("Odd Row Color"),
+ P_("Color to use for odd rows"),
GDK_TYPE_COLOR,
G_PARAM_READABLE));
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
NULL, NULL,
- _gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ _gtk_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
tree_view_signals[UNSELECT_ALL] =
g_signal_new ("unselect_all",
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, unselect_all),
NULL, NULL,
- _gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ _gtk_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
tree_view_signals[SELECT_CURSOR_ROW] =
g_signal_new ("select_cursor_row",
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
NULL, NULL,
- _gtk_marshal_VOID__BOOLEAN,
- G_TYPE_NONE, 1,
+ _gtk_marshal_BOOLEAN__BOOLEAN,
+ G_TYPE_BOOLEAN, 1,
G_TYPE_BOOLEAN);
tree_view_signals[TOGGLE_CURSOR_ROW] =
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
NULL, NULL,
- _gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ _gtk_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
g_signal_new ("expand_collapse_cursor_row",
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
NULL, NULL,
- _gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
- G_TYPE_NONE, 3,
+ _gtk_marshal_BOOLEAN__BOOLEAN_BOOLEAN_BOOLEAN,
+ G_TYPE_BOOLEAN, 3,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN,
G_TYPE_BOOLEAN);
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
NULL, NULL,
- _gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ _gtk_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
tree_view_signals[START_INTERACTIVE_SEARCH] =
g_signal_new ("start_interactive_search",
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
NULL, NULL,
- _gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ _gtk_marshal_BOOLEAN__NONE,
+ G_TYPE_BOOLEAN, 0);
/* Key bindings */
gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
GTK_MOVEMENT_DISPLAY_LINES, -1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Up, 0,
+ GTK_MOVEMENT_DISPLAY_LINES, -1);
gtk_tree_view_add_move_binding (binding_set, GDK_Down, 0,
GTK_MOVEMENT_DISPLAY_LINES, 1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Down, 0,
+ GTK_MOVEMENT_DISPLAY_LINES, 1);
gtk_tree_view_add_move_binding (binding_set, GDK_p, GDK_CONTROL_MASK,
GTK_MOVEMENT_DISPLAY_LINES, -1);
gtk_tree_view_add_move_binding (binding_set, GDK_Home, 0,
GTK_MOVEMENT_BUFFER_ENDS, -1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Home, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, -1);
gtk_tree_view_add_move_binding (binding_set, GDK_End, 0,
GTK_MOVEMENT_BUFFER_ENDS, 1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_End, 0,
+ GTK_MOVEMENT_BUFFER_ENDS, 1);
gtk_tree_view_add_move_binding (binding_set, GDK_Page_Up, 0,
GTK_MOVEMENT_PAGES, -1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Up, 0,
+ GTK_MOVEMENT_PAGES, -1);
gtk_tree_view_add_move_binding (binding_set, GDK_Page_Down, 0,
GTK_MOVEMENT_PAGES, 1);
+ gtk_tree_view_add_move_binding (binding_set, GDK_KP_Page_Down, 0,
+ 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_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
G_TYPE_INT, -1);
- gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, "move_cursor", 2,
+ 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_Left, GDK_CONTROL_MASK, "move_cursor", 2,
+ 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|GDK_SHIFT_MASK, "move_cursor", 2,
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK,
+ "move_cursor", 2,
G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
G_TYPE_INT, 1);
- gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK,
+ "move_cursor", 2,
+ G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ G_TYPE_INT, -1);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_CONTROL_MASK,
+ "move_cursor", 2,
+ G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ G_TYPE_INT, 1);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_CONTROL_MASK,
+ "move_cursor", 2,
G_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
G_TYPE_INT, -1);
gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Return, 0, "select_cursor_row", 1,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_ISO_Enter, 0, "select_cursor_row", 1,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Enter, 0, "select_cursor_row", 1,
+ G_TYPE_BOOLEAN, TRUE);
/* expand and collapse rows */
gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
- G_TYPE_BOOLEAN, FALSE,
+ 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, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Multiply, 0,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_slash, 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_Divide, 0,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, FALSE);
+
/* Not doable on US keyboards */
gtk_binding_entry_add_signal (binding_set, GDK_plus, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
- G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, 0, "expand_collapse_cursor_row", 3,
- G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
- G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Add, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE);
- gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Right, GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Right,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Right,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_minus, 0, "expand_collapse_cursor_row", 3,
- G_TYPE_BOOLEAN, FALSE,
+ 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, FALSE,
+ G_TYPE_BOOLEAN, TRUE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE);
gtk_binding_entry_add_signal (binding_set, GDK_KP_Subtract, 0, "expand_collapse_cursor_row", 3,
- 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_Subtract, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, TRUE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Left, GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE);
- gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_SHIFT_MASK, "expand_collapse_cursor_row", 3,
+ gtk_binding_entry_add_signal (binding_set, GDK_Left,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, FALSE,
+ G_TYPE_BOOLEAN, TRUE);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Left,
+ GDK_CONTROL_MASK | GDK_SHIFT_MASK,
+ "expand_collapse_cursor_row", 3,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, FALSE,
G_TYPE_BOOLEAN, TRUE);
gtk_widget_set_redraw_on_allocate (GTK_WIDGET (tree_view), FALSE);
- tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
+ tree_view->priv->flags = GTK_TREE_VIEW_SHOW_EXPANDERS
+ | GTK_TREE_VIEW_DRAW_KEYFOCUS
+ | GTK_TREE_VIEW_HEADERS_VISIBLE;
/* We need some padding */
tree_view->priv->dy = 0;
tree_view->priv->reorderable = FALSE;
tree_view->priv->presize_handler_timer = 0;
tree_view->priv->scroll_sync_timer = 0;
+ tree_view->priv->fixed_height = -1;
+ tree_view->priv->fixed_height_mode = 0;
tree_view->priv->fixed_height_check = 0;
gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
tree_view->priv->search_column = -1;
tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
tree_view->priv->search_equal_func = gtk_tree_view_search_equal_func;
+ tree_view->priv->init_hadjust_value = TRUE;
+ tree_view->priv->width = 0;
}
\f
case PROP_SEARCH_COLUMN:
gtk_tree_view_set_search_column (tree_view, g_value_get_int (value));
break;
+ case PROP_FIXED_HEIGHT_MODE:
+ gtk_tree_view_set_fixed_height_mode (tree_view, g_value_get_boolean (value));
+ break;
default:
break;
}
case PROP_SEARCH_COLUMN:
g_value_set_int (value, tree_view->priv->search_column);
break;
+ case PROP_FIXED_HEIGHT_MODE:
+ g_value_set_boolean (value, tree_view->priv->fixed_height_mode);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
tree_view->priv->anchor = NULL;
/* destroy interactive search dialog */
- search_dialog = g_object_get_data (G_OBJECT (tree_view),
- GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
- if (search_dialog)
- gtk_tree_view_search_dialog_destroy (search_dialog,
- tree_view);
+ if (tree_view->priv->search_window)
+ {
+ gtk_widget_destroy (tree_view->priv->search_window);
+ tree_view->priv->search_window = NULL;
+ tree_view->priv->search_entry = NULL;
+ }
- if (tree_view->priv->search_user_data)
+ if (tree_view->priv->search_destroy)
{
(* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
tree_view->priv->search_user_data = NULL;
if (tree_view->priv->scroll_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->scroll_timeout);
+ g_source_remove (tree_view->priv->scroll_timeout);
tree_view->priv->scroll_timeout = 0;
}
if (tree_view->priv->open_dest_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->open_dest_timeout);
+ g_source_remove (tree_view->priv->open_dest_timeout);
tree_view->priv->open_dest_timeout = 0;
}
if (tree_view->priv->expand_collapse_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ g_source_remove (tree_view->priv->expand_collapse_timeout);
tree_view->priv->expand_collapse_timeout = 0;
}
if (tree_view->priv->presize_handler_timer != 0)
{
- gtk_timeout_remove (tree_view->priv->presize_handler_timer);
+ g_source_remove (tree_view->priv->presize_handler_timer);
tree_view->priv->presize_handler_timer = 0;
}
if (tree_view->priv->validate_rows_timer != 0)
{
- gtk_timeout_remove (tree_view->priv->validate_rows_timer);
+ g_source_remove (tree_view->priv->validate_rows_timer);
tree_view->priv->validate_rows_timer = 0;
}
if (tree_view->priv->scroll_sync_timer != 0)
{
- gtk_timeout_remove (tree_view->priv->scroll_sync_timer);
+ g_source_remove (tree_view->priv->scroll_sync_timer);
tree_view->priv->scroll_sync_timer = 0;
}
}
+/* Called only by ::size_request */
static void
gtk_tree_view_update_size (GtkTreeView *tree_view)
{
if (tree_view->priv->model == NULL)
{
tree_view->priv->width = 0;
+ tree_view->priv->prev_width = 0;
tree_view->priv->height = 0;
return;
}
+ tree_view->priv->prev_width = tree_view->priv->width;
tree_view->priv->width = 0;
/* keep this in sync with size_allocate below */
for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
tree_view = GTK_TREE_VIEW (widget);
- /* we validate 50 rows initially just to make sure we have some size */
- /* in practice, with a lot of static lists, this should get a good width */
+ /* we validate GTK_TREE_VIEW_NUM_ROWS_PER_IDLE rows initially just to make
+ * sure we have some size. In practice, with a lot of static lists, this
+ * should get a good width.
+ */
validate_rows (tree_view);
gtk_tree_view_size_request_columns (tree_view);
gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
}
}
+
+static void
+invalidate_column (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column)
+{
+ gint column_offset = 0;
+ GList *list;
+ GtkWidget *widget = GTK_WIDGET (tree_view);
+ gboolean rtl;
+
+ if (!GTK_WIDGET_REALIZED (widget))
+ return;
+
+ 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 *tmpcolumn = list->data;
+ if (tmpcolumn == column)
+ {
+ GdkRectangle invalid_rect;
+
+ invalid_rect.x = column_offset;
+ invalid_rect.y = 0;
+ invalid_rect.width = column->width;
+ invalid_rect.height = widget->allocation.height;
+
+ gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
+ break;
+ }
+
+ column_offset += tmpcolumn->width;
+ }
+}
+
+static void
+invalidate_last_column (GtkTreeView *tree_view)
+{
+ GList *last_column;
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+
+ for (last_column = (rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns));
+ last_column;
+ last_column = (rtl ? last_column->next : last_column->prev))
+ {
+ if (GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
+ {
+ invalidate_column (tree_view, last_column->data);
+ return;
+ }
+ }
+}
+
+static gint
+gtk_tree_view_get_real_requested_width_from_column (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column)
+{
+ gint real_requested_width;
+
+ if (column->use_resized_width)
+ {
+ real_requested_width = column->resized_width;
+ }
+ else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+ {
+ real_requested_width = column->fixed_width;
+ }
+ else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
+ {
+ real_requested_width = MAX (column->requested_width, column->button_request);
+ }
+ else
+ {
+ real_requested_width = column->requested_width;
+ if (real_requested_width < 0)
+ real_requested_width = 0;
+ }
+
+ if (column->min_width != -1)
+ real_requested_width = MAX (real_requested_width, column->min_width);
+ if (column->max_width != -1)
+ real_requested_width = MIN (real_requested_width, column->max_width);
+
+ return real_requested_width;
+}
+
/* GtkWidget::size_allocate helper */
static void
gtk_tree_view_size_allocate_columns (GtkWidget *widget)
{
GtkTreeView *tree_view;
- GList *list, *last_column;
+ GList *list, *first_column, *last_column;
GtkTreeViewColumn *column;
GtkAllocation allocation;
gint width = 0;
-
+ gint extra, extra_per_column;
+ gint full_requested_width = 0;
+ gint number_of_expand_columns = 0;
+ gboolean rtl;
+
tree_view = GTK_TREE_VIEW (widget);
for (last_column = g_list_last (tree_view->priv->columns);
if (last_column == NULL)
return;
+ for (first_column = g_list_first (tree_view->priv->columns);
+ first_column && !(GTK_TREE_VIEW_COLUMN (first_column->data)->visible);
+ first_column = first_column->next)
+ ;
+
allocation.y = 0;
allocation.height = tree_view->priv->header_height;
+ rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
+
+ /* find out how many extra space and expandable columns we have */
for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
+ {
+ column = (GtkTreeViewColumn *)list->data;
+
+ if (!column->visible)
+ continue;
+
+ full_requested_width += gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
+
+ if (column->expand)
+ number_of_expand_columns++;
+ }
+
+ extra = MAX (widget->allocation.width - full_requested_width, 0);
+ if (number_of_expand_columns > 0)
+ extra_per_column = extra/number_of_expand_columns;
+ else
+ extra_per_column = 0;
+
+ for (list = (rtl ? last_column : first_column);
+ list != (rtl ? first_column->prev : last_column->next);
+ list = (rtl ? list->prev : list->next))
{
gint real_requested_width = 0;
+ gint old_width;
+
column = list->data;
+ old_width = column->width;
+
if (!column->visible)
continue;
continue;
}
- if (column->use_resized_width)
- {
- real_requested_width = column->resized_width;
- }
- else if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
- {
- real_requested_width = column->fixed_width;
- }
- else if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
- {
- real_requested_width = MAX (column->requested_width, column->button_request);
- }
- else
- {
- real_requested_width = column->requested_width;
- if (real_requested_width < 0)
- real_requested_width = 0;
- }
-
- if (column->min_width != -1)
- real_requested_width = MAX (real_requested_width, column->min_width);
- if (column->max_width != -1)
- real_requested_width = MIN (real_requested_width, column->max_width);
+ real_requested_width = gtk_tree_view_get_real_requested_width_from_column (tree_view, column);
allocation.x = width;
column->width = real_requested_width;
- if (list == last_column &&
- width + real_requested_width < widget->allocation.width)
+
+ if (column->expand)
{
- column->width += (widget->allocation.width - column->width - width);
+ if (number_of_expand_columns == 1)
+ {
+ /* We add the remander to the last column as
+ * */
+ column->width += extra;
+ }
+ else
+ {
+ column->width += extra_per_column;
+ extra -= extra_per_column;
+ number_of_expand_columns --;
+ }
}
+ else if (number_of_expand_columns == 0 &&
+ list == last_column)
+ {
+ column->width += extra;
+ }
+
g_object_notify (G_OBJECT (column), "width");
+
allocation.width = column->width;
width += column->width;
+
+ if (column->width > old_width)
+ invalidate_column (tree_view, column);
+
gtk_widget_size_allocate (column->button, &allocation);
+
if (column->window)
gdk_window_move_resize (column->window,
- allocation.x + allocation.width - TREE_VIEW_DRAG_WIDTH/2,
+ allocation.x + (rtl ? 0 : allocation.width) - TREE_VIEW_DRAG_WIDTH/2,
allocation.y,
TREE_VIEW_DRAG_WIDTH, allocation.height);
}
}
-static void
-invalidate_last_column (GtkTreeView *tree_view)
-{
- GList *list, *last_column;
- gint last_column_x;
- GtkWidget *widget = GTK_WIDGET (tree_view);
-
- for (last_column = g_list_last (tree_view->priv->columns);
- last_column && !(GTK_TREE_VIEW_COLUMN (last_column->data)->visible);
- last_column = last_column->prev)
- ;
-
- last_column_x = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- GtkTreeViewColumn *column = list->data;
- if (list == last_column)
- {
- GdkRectangle invalid_rect;
-
- invalid_rect.x = last_column_x;
- invalid_rect.y = 0;
- invalid_rect.width = column->width;
- invalid_rect.height = widget->allocation.height;
-
- gdk_window_invalidate_rect (widget->window, &invalid_rect, TRUE);
- break;
- }
-
- last_column_x += column->width;
- }
-}
static void
gtk_tree_view_size_allocate (GtkWidget *widget,
GList *tmp_list;
GtkTreeView *tree_view;
gboolean width_changed = FALSE;
+ gboolean dy_changed = FALSE;
+ gint old_width = widget->allocation.width;
g_return_if_fail (GTK_IS_TREE_VIEW (widget));
tree_view->priv->hadjustment->lower = 0;
tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->page_size, tree_view->priv->width);
- if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
- tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
+ if (gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL)
+ {
+ if (allocation->width < tree_view->priv->width)
+ {
+ if (tree_view->priv->init_hadjust_value)
+ {
+ tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
+ tree_view->priv->init_hadjust_value = FALSE;
+ }
+ else if(allocation->width != old_width)
+ tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->hadjustment->value - allocation->width + old_width, 0, tree_view->priv->width - allocation->width);
+ else
+ tree_view->priv->hadjustment->value = CLAMP(tree_view->priv->width - (tree_view->priv->prev_width - tree_view->priv->hadjustment->value), 0, tree_view->priv->width - allocation->width);
+ }
+ else
+ {
+ tree_view->priv->hadjustment->value = 0;
+ tree_view->priv->init_hadjust_value = TRUE;
+ }
+ }
+ else
+ if (tree_view->priv->hadjustment->value + allocation->width > tree_view->priv->width)
+ tree_view->priv->hadjustment->value = MAX (tree_view->priv->width - allocation->width, 0);
+
gtk_adjustment_changed (tree_view->priv->hadjustment);
tree_view->priv->vadjustment->page_size = allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view);
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->page_size, tree_view->priv->height);
if (tree_view->priv->vadjustment->value + allocation->height - TREE_VIEW_HEADER_HEIGHT (tree_view) > tree_view->priv->height)
- gtk_adjustment_set_value (tree_view->priv->vadjustment,
- MAX (tree_view->priv->height - tree_view->priv->vadjustment->page_size, 0));
+ {
+ double before = tree_view->priv->vadjustment->value;
+ gtk_adjustment_set_value (tree_view->priv->vadjustment,
+ MAX (tree_view->priv->height - tree_view->priv->vadjustment->page_size, 0));
+ if (before != tree_view->priv->vadjustment->value)
+ dy_changed = TRUE;
+ }
+
gtk_adjustment_changed (tree_view->priv->vadjustment);
if (GTK_WIDGET_REALIZED (widget))
gtk_tree_view_size_allocate_columns (widget);
- if (GTK_WIDGET_REALIZED (widget) && width_changed)
- invalidate_last_column (tree_view);
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gboolean has_expand_column = FALSE;
+ for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
+ {
+ if (gtk_tree_view_column_get_expand (GTK_TREE_VIEW_COLUMN (tmp_list->data)))
+ {
+ has_expand_column = TRUE;
+ break;
+ }
+ }
+
+ /* This little hack only works if we have an LTR locale, and no column has the */
+ if (width_changed)
+ {
+ if (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_LTR &&
+ ! has_expand_column)
+ invalidate_last_column (tree_view);
+ else
+ gtk_widget_queue_draw (widget);
+ }
+
+ if (dy_changed)
+ gtk_widget_queue_draw (widget);
+ }
}
static gboolean
GdkRectangle cell_area;
gint vertical_separator;
gint horizontal_separator;
+ gboolean rtl;
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);
+ rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
gtk_tree_view_stop_editing (tree_view, FALSE);
gtk_widget_style_get (widget,
"vertical_separator", &vertical_separator,
"horizontal_separator", &horizontal_separator,
NULL);
+
+ /* Because grab_focus can cause reentrancy, we delay grab_focus until after
+ * we're done handling the button press.
+ */
+ if (event->window == tree_view->priv->bin_window &&
+ tree_view->priv->tree != NULL)
+ {
+ }
+
if (event->window == tree_view->priv->bin_window &&
tree_view->priv->tree != NULL)
{
GtkTreeViewColumn *column = NULL;
GtkCellRenderer *focus_cell = NULL;
gint column_handled_click = FALSE;
- gboolean emit_row_activated = FALSE;
-
- if (!GTK_WIDGET_HAS_FOCUS (widget))
- gtk_widget_grab_focus (widget);
- GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ gboolean row_double_click = FALSE;
+ gboolean rtl;
+ GtkWidget *grab_widget;
/* are we in an arrow? */
if (tree_view->priv->prelight_node &&
tree_view->priv->button_pressed_node = tree_view->priv->prelight_node;
tree_view->priv->button_pressed_tree = tree_view->priv->prelight_tree;
gtk_tree_view_draw_arrow (GTK_TREE_VIEW (widget),
- tree_view->priv->prelight_tree,
+ tree_view->priv->prelight_tree,
tree_view->priv->prelight_node,
event->x,
event->y);
}
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_widget_grab_focus (widget);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
return TRUE;
}
y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
if (node == NULL)
- /* We clicked in dead space */
- return TRUE;
+ {
+ /* We clicked in dead space */
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_widget_grab_focus (widget);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ return TRUE;
+ }
/* Get the path and the node */
path = _gtk_tree_view_find_path (tree_view, tree, node);
tree_view->priv->expander_size);
background_area.x = 0;
+
/* Let the column have a chance at selecting it. */
- 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))
{
column = list->data;
if (column == NULL)
{
gtk_tree_path_free (path);
-
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_widget_grab_focus (widget);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
return FALSE;
}
+ tree_view->priv->focus_column = column;
+
/* decide if we edit */
- if (event->type == GDK_BUTTON_PRESS &&
+ if (event->type == GDK_BUTTON_PRESS && event->button == 1 &&
!(event->state & gtk_accelerator_get_default_mod_mask ()))
{
GtkTreePath *anchor;
/* select */
pre_val = tree_view->priv->vadjustment->value;
- tree_view->priv->focus_column = column;
- focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
- if (focus_cell)
- gtk_tree_view_column_focus_cell (column, focus_cell);
+ /* we only handle selection modifications on the first button press
+ */
+ if (event->type == GDK_BUTTON_PRESS)
+ {
+ if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ tree_view->priv->ctrl_pressed = TRUE;
+ if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+ tree_view->priv->shift_pressed = TRUE;
- if (event->state & GDK_CONTROL_MASK)
- {
- gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
- gtk_tree_view_real_toggle_cursor_row (tree_view);
- }
- else if (event->state & GDK_SHIFT_MASK)
- {
- gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
- gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
- }
- else
- {
- gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
- }
+ focus_cell = _gtk_tree_view_column_get_cell_at_pos (column, event->x - background_area.x);
+ if (focus_cell)
+ gtk_tree_view_column_focus_cell (column, focus_cell);
+
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ gtk_tree_view_real_toggle_cursor_row (tree_view);
+ }
+ else if (event->state & GDK_SHIFT_MASK)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE, TRUE);
+ gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
+ }
+ else
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
+ }
+
+ tree_view->priv->ctrl_pressed = FALSE;
+ tree_view->priv->shift_pressed = FALSE;
+ }
/* the treeview may have been scrolled because of _set_cursor,
* correct here
/* Save press to possibly begin a drag
*/
- if (!column_handled_click &&
+ grab_widget = gtk_grab_get_current ();
+ if ((grab_widget == NULL || grab_widget == widget) &&
+ !column_handled_click &&
tree_view->priv->pressed_button < 0)
{
tree_view->priv->pressed_button = event->button;
tree_view->priv->press_start_y = event->y;
}
- if (event->button == 1 && event->type == GDK_2BUTTON_PRESS &&
- tree_view->priv->last_button_press)
- {
- GtkTreePath *lsc;
+ /* Test if a double click happened on the same row. */
+ if (event->button == 1)
+ {
+ /* We also handle triple clicks here, because a user could have done
+ * a first click and a second double click on different rows.
+ */
+ if ((event->type == GDK_2BUTTON_PRESS
+ || event->type == GDK_3BUTTON_PRESS)
+ && tree_view->priv->last_button_press)
+ {
+ GtkTreePath *lsc;
- lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
+ lsc = gtk_tree_row_reference_get_path (tree_view->priv->last_button_press);
- if (tree_view->priv->last_button_press)
- gtk_tree_row_reference_free (tree_view->priv->last_button_press);
- if (tree_view->priv->last_button_press_2)
- gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
- tree_view->priv->last_button_press = NULL;
- tree_view->priv->last_button_press_2 = NULL;
-
- if (lsc)
- {
- if (!gtk_tree_path_compare (lsc, path))
- emit_row_activated = TRUE;
- gtk_tree_path_free (lsc);
- }
- }
- else if (event->button == 1 && event->type == GDK_BUTTON_PRESS)
- {
- if (tree_view->priv->last_button_press)
- gtk_tree_row_reference_free (tree_view->priv->last_button_press);
- tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
- tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
- }
+ if (lsc)
+ {
+ row_double_click = !gtk_tree_path_compare (lsc, path);
+ gtk_tree_path_free (lsc);
+ }
+ }
- GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ if (row_double_click)
+ {
+ if (tree_view->priv->last_button_press)
+ gtk_tree_row_reference_free (tree_view->priv->last_button_press);
+ if (tree_view->priv->last_button_press_2)
+ gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
+ tree_view->priv->last_button_press = NULL;
+ tree_view->priv->last_button_press_2 = NULL;
+ }
+ else
+ {
+ if (tree_view->priv->last_button_press)
+ gtk_tree_row_reference_free (tree_view->priv->last_button_press);
+ tree_view->priv->last_button_press = tree_view->priv->last_button_press_2;
+ tree_view->priv->last_button_press_2 = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, path);
+ }
+ }
- if (emit_row_activated)
+ if (row_double_click)
{
gtk_grab_remove (widget);
gtk_tree_view_row_activated (tree_view, path, column);
+
+ if (tree_view->priv->pressed_button == event->button)
+ tree_view->priv->pressed_button = -1;
}
gtk_tree_path_free (path);
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_widget_grab_focus (widget);
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+
return TRUE;
}
gtk_tree_view_column_get_sizing (column) != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
{
_gtk_tree_view_column_autosize (tree_view, column);
- break;
+ return TRUE;
}
if (gdk_pointer_grab (column->window, FALSE,
gtk_widget_grab_focus (widget);
tree_view->priv->drag_pos = i;
- tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
- break;
+ tree_view->priv->x_drag = column->button->allocation.x + (rtl ? 0 : column->button->allocation.width);
+ return TRUE;
}
}
- return TRUE;
+ return FALSE;
}
/* GtkWidget::button_release_event helper */
GdkEventButton *event)
{
GtkTreeView *tree_view;
+ gboolean rtl;
tree_view = GTK_TREE_VIEW (widget);
+ rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
gdk_display_pointer_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
gdk_display_keyboard_ungrab (gtk_widget_get_display (widget), GDK_CURRENT_TIME);
gtk_widget_grab_focus (tree_view->priv->drag_column->button);
- if (tree_view->priv->cur_reorder &&
- tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
- gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
- tree_view->priv->cur_reorder->left_column);
+ if (rtl)
+ {
+ if (tree_view->priv->cur_reorder &&
+ tree_view->priv->cur_reorder->right_column != tree_view->priv->drag_column)
+ gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
+ tree_view->priv->cur_reorder->right_column);
+ }
+ else
+ {
+ if (tree_view->priv->cur_reorder &&
+ tree_view->priv->cur_reorder->left_column != tree_view->priv->drag_column)
+ gtk_tree_view_move_column_after (tree_view, tree_view->priv->drag_column,
+ tree_view->priv->cur_reorder->left_column);
+ }
tree_view->priv->drag_column = NULL;
gdk_window_hide (tree_view->priv->drag_window);
return TRUE;
}
+#if 0
+static gboolean
+gtk_tree_view_configure (GtkWidget *widget,
+ GdkEventConfigure *event)
+{
+ GtkTreeView *tree_view;
+
+ tree_view = GTK_TREE_VIEW (widget);
+ tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+
+ return FALSE;
+}
+#endif
/* GtkWidget::motion_event function set.
*/
}
static void
-do_unprelight (GtkTreeView *tree_view,
- /* these are in tree window coords */
- gint x,
- gint y)
+do_prelight (GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node,
+ /* these are in tree_window coords */
+ gint x,
+ gint y)
{
- if (tree_view->priv->prelight_node == NULL)
- return;
+ if (tree_view->priv->prelight_tree == tree &&
+ tree_view->priv->prelight_node == node)
+ {
+ /* We are still on the same node,
+ but we might need to take care of the arrow */
+
+ if (tree && node)
+ {
+ gboolean over_arrow;
+ gboolean flag_set;
- GTK_RBNODE_UNSET_FLAG (tree_view->priv->prelight_node, GTK_RBNODE_IS_PRELIT);
+ over_arrow = coords_are_over_arrow (tree_view, tree, node, x, y);
+ flag_set = 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) &&
- !coords_are_over_arrow (tree_view,
- tree_view->priv->prelight_tree,
- tree_view->priv->prelight_node,
- x,
- y))
- /* We need to unprelight the old arrow. */
+ if (over_arrow != flag_set)
+ {
+ if (over_arrow)
+ GTK_TREE_VIEW_SET_FLAG (tree_view,
+ GTK_TREE_VIEW_ARROW_PRELIT);
+ else
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view,
+ GTK_TREE_VIEW_ARROW_PRELIT);
+
+ gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
+ }
+ }
+
+ return;
+ }
+
+ if (tree_view->priv->prelight_tree && tree_view->priv->prelight_node)
{
- GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
+ /* Unprelight the old node and arrow */
- gtk_tree_view_draw_arrow (tree_view,
- tree_view->priv->prelight_tree,
- tree_view->priv->prelight_node,
- x,
- y);
+ 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))
+ {
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
+
+ gtk_tree_view_draw_arrow (tree_view,
+ tree_view->priv->prelight_tree,
+ tree_view->priv->prelight_node,
+ x,
+ y);
+ }
+
+ _gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->prelight_tree,
+ tree_view->priv->prelight_node,
+ NULL);
}
- tree_view->priv->prelight_node = NULL;
- tree_view->priv->prelight_tree = NULL;
-}
-static void
-do_prelight (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkRBNode *node,
- /* these are in tree_window coords */
- gint x,
- gint y)
-{
+ /* Set the new prelight values */
+
+ tree_view->priv->prelight_node = node;
+ tree_view->priv->prelight_tree = tree;
+
+ if (!node || !tree)
+ return;
+
+ /* Prelight the new node and arrow */
+
if (coords_are_over_arrow (tree_view, tree, node, x, y))
{
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
- }
- tree_view->priv->prelight_node = node;
- tree_view->priv->prelight_tree = tree;
+ gtk_tree_view_draw_arrow (tree_view, tree, node, x, y);
+ }
GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_PRELIT);
+
+ _gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
}
static void
ensure_unprelighted (GtkTreeView *tree_view)
{
- do_unprelight (tree_view, -1000, -1000); /* coords not possibly over an arrow */
+ do_prelight (tree_view,
+ NULL, NULL,
+ -1000, -1000); /* coords not possibly over an arrow */
+
g_assert (tree_view->priv->prelight_node == NULL);
}
gint mouse_x;
gdk_window_get_pointer (tree_view->priv->header_window, &mouse_x, NULL, NULL);
-
for (list = tree_view->priv->column_drag_info; list; list = list->next)
{
reorder = (GtkTreeViewColumnReorder *) list->data;
x = CLAMP (x + (gint)event->x - column->drag_x, 0,
MAX (tree_view->priv->width, GTK_WIDGET (tree_view)->allocation.width) - column->button->allocation.width);
gdk_window_move (tree_view->priv->drag_window, x, y);
-
+
/* autoscroll, if needed */
gtk_tree_view_horizontal_autoscroll (tree_view);
/* Update the current reorder position and arrow; */
GtkRBTree *tree;
GtkRBNode *node;
gint new_y;
- GtkRBTree *old_prelight_tree;
- GtkRBNode *old_prelight_node;
- gboolean old_arrow_prelit;
tree_view = (GtkTreeView *) widget;
if (tree_view->priv->tree == NULL)
return FALSE;
- gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
-
- old_prelight_tree = tree_view->priv->prelight_tree;
- old_prelight_node = tree_view->priv->prelight_node;
- old_arrow_prelit = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
+ /* only check for an initiated drag when a button is pressed */
+ if (tree_view->priv->pressed_button >= 0)
+ gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
if (new_y < 0)
new_y = 0;
- do_unprelight (tree_view, event->x, event->y);
- _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
- if (tree == NULL)
- return TRUE;
+ _gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
/* If we are currently pressing down a button, we don't want to prelight anything else. */
if ((tree_view->priv->button_pressed_node != NULL) &&
(tree_view->priv->button_pressed_node != node))
- return TRUE;
-
+ node = NULL;
do_prelight (tree_view, tree, node, event->x, event->y);
- if (old_prelight_node != tree_view->priv->prelight_node)
- {
- if (old_prelight_node)
- {
- _gtk_tree_view_queue_draw_node (tree_view,
- old_prelight_tree,
- old_prelight_node,
- NULL);
- }
- if (tree_view->priv->prelight_node)
- {
- _gtk_tree_view_queue_draw_node (tree_view,
- tree_view->priv->prelight_tree,
- tree_view->priv->prelight_node,
- NULL);
- }
- }
- else if (old_arrow_prelit != GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_ARROW_PRELIT))
- {
- if (tree_view->priv->prelight_node)
- {
- _gtk_tree_view_queue_draw_node (tree_view,
- tree_view->priv->prelight_tree,
- tree_view->priv->prelight_node,
- NULL);
- }
- }
return TRUE;
}
gint focus_line_width;
gboolean allow_rules;
gboolean has_special_cell;
+ gboolean rtl;
+ gint n_visible_columns;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
+ rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
+
tree_view = GTK_TREE_VIEW (widget);
gtk_widget_style_get (widget,
gdk_drawable_get_size (tree_view->priv->bin_window,
&bin_window_width, NULL);
- for (last_column = g_list_last (tree_view->priv->columns);
+
+ n_visible_columns = 0;
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ if (! GTK_TREE_VIEW_COLUMN (list->data)->visible)
+ continue;
+ n_visible_columns ++;
+ }
+
+ /* Find the last column */
+ for (last_column = rtl ? g_list_first (tree_view->priv->columns) : g_list_last (tree_view->priv->columns);
last_column &&
!(GTK_TREE_VIEW_COLUMN (last_column->data)->visible) &&
GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button);
- last_column = last_column->prev)
+ last_column = rtl ? last_column->next : last_column->prev)
;
/* Actually process the expose event. To do this, we want to
has_special_cell = gtk_tree_view_has_special_cell (tree_view);
- for (list = tree_view->priv->columns; list; list = list->next)
+ 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;
}
if (column->show_sort_indicator)
- flags |= GTK_CELL_RENDERER_SORTED;
+ flags |= GTK_CELL_RENDERER_SORTED;
else
flags &= ~GTK_CELL_RENDERER_SORTED;
+ if (cursor == node)
+ flags |= GTK_CELL_RENDERER_FOCUSED;
+ else
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
background_area.x = cell_offset;
background_area.width = column->width;
*/
if (allow_rules && tree_view->priv->has_rules)
{
- if (flags & GTK_CELL_RENDERER_SORTED)
+ if ((flags & GTK_CELL_RENDERER_SORTED) &&
+ n_visible_columns >= 3)
{
if (parity)
detail = "cell_odd_ruled_sorted";
}
else
{
- if (flags & GTK_CELL_RENDERER_SORTED)
+ if ((flags & GTK_CELL_RENDERER_SORTED) &&
+ n_visible_columns >= 3)
{
if (parity)
detail = "cell_odd_sorted";
if (gtk_tree_view_is_expander_column (tree_view, column) &&
TREE_VIEW_DRAW_EXPANDERS(tree_view))
{
- cell_area.x += depth * tree_view->priv->expander_size;
+ 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
{
GtkTreeView *tree_view = (GtkTreeView *) widget;
GList *list;
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
{
return TRUE;
}
- /* FIXME: this is prolly broken when we go bidi */
if (tree_view->priv->columns && (event->state & GDK_SHIFT_MASK)
- && (event->keyval == GDK_Left || event->keyval == GDK_Right))
+ && (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 (!column->resizable)
return TRUE;
- if (event->keyval == GDK_Left)
+ if (event->keyval == GDK_Left || event->keyval == GDK_KP_Left)
{
column->resized_width = MAX (column->resized_width,
column->width);
gtk_widget_queue_resize (widget);
return TRUE;
}
- else if (event->keyval == GDK_Right)
+ else if (event->keyval == GDK_Right
+ || event->keyval == GDK_KP_Right)
{
column->resized_width = MAX (column->resized_width,
column->width);
}
}
- /* FIXME: broken when we go bidi? */
if (tree_view->priv->columns && (event->state & GDK_CONTROL_MASK) &&
- (event->keyval == GDK_Left || event->keyval == GDK_Right
- || event->keyval == GDK_Home || event->keyval == GDK_End))
+ (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
+ || event->keyval == GDK_End || event->keyval == GDK_KP_End))
{
list = tree_view->priv->columns;
while (list)
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
if (GTK_WIDGET_HAS_FOCUS (column->button))
{
- if (event->keyval == GDK_Left)
+ if (event->keyval == (rtl ? GDK_Right : GDK_Left)
+ || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
{
GtkTreeViewColumn *col;
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_LEFT);
gtk_tree_view_move_column_after (tree_view, column, col);
return TRUE;
}
- else if (event->keyval == GDK_Right)
+ else if (event->keyval == (rtl ? GDK_Left : GDK_Right)
+ || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
{
GtkTreeViewColumn *col;
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_RIGHT);
gtk_tree_view_move_column_after (tree_view, column, col);
return TRUE;
}
- else if (event->keyval == GDK_Home)
+ else if (event->keyval == GDK_Home
+ || event->keyval == GDK_KP_Home)
{
GtkTreeViewColumn *col;
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_HOME);
gtk_tree_view_move_column_after (tree_view, column, col);
return TRUE;
}
- else if (event->keyval == GDK_End)
+ else if (event->keyval == GDK_End || event->keyval == GDK_KP_End)
{
GtkTreeViewColumn *col;
col = gtk_tree_view_get_drop_column (tree_view, column, DROP_END);
}
}
- /* FIXME: this is prolly broken when we go bidi */
if (tree_view->priv->columns &&
- (event->keyval == GDK_Left || event->keyval == GDK_Right))
+ GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE) &&
+ (event->keyval == GDK_Left || event->keyval == GDK_KP_Left
+ || event->keyval == GDK_Right || event->keyval == GDK_KP_Right))
{
gint width = 0;
list = tree_view->priv->columns;
GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN (list->data);
if (GTK_WIDGET_HAS_FOCUS (column->button))
{
- if (event->keyval == GDK_Left && list->prev)
+ if ((event->keyval == (rtl ? GDK_Right : GDK_Left)
+ || event->keyval == (rtl ? GDK_KP_Right : GDK_KP_Left))
+ && list->prev)
{
GList *tmp;
gtk_adjustment_set_value (tree_view->priv->hadjustment, CLAMP (width, tree_view->priv->hadjustment->lower, tree_view->priv->hadjustment->upper - tree_view->priv->hadjustment->page_size));
return TRUE;
}
- else if (event->keyval == GDK_Right && list->next)
+ else if ((event->keyval == (rtl ? GDK_Left : GDK_Right)
+ || event->keyval == (rtl ? GDK_KP_Left : GDK_KP_Right))
+ && list->next)
{
GList *tmp;
}
}
- return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
+ if ((* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event))
+ return TRUE;
+
+ return FALSE;
}
/* FIXME Is this function necessary? Can I get an enter_notify event
new_y = 0;
_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
- if (node == NULL)
- return FALSE;
-
do_prelight (tree_view, tree, node, event->x, event->y);
- if (tree_view->priv->prelight_node)
- _gtk_tree_view_queue_draw_node (tree_view,
- tree_view->priv->prelight_tree,
- tree_view->priv->prelight_node,
- NULL);
-
return TRUE;
}
gtk_tree_view_focus_out (GtkWidget *widget,
GdkEventFocus *event)
{
- GtkWidget *search_dialog;
+ GtkTreeView *tree_view;
+
+ tree_view = GTK_TREE_VIEW (widget);
gtk_widget_queue_draw (widget);
/* destroy interactive search dialog */
- search_dialog = g_object_get_data (G_OBJECT (widget),
- GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
- if (search_dialog)
- gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
+ if (tree_view->priv->search_window)
+ gtk_tree_view_search_dialog_hide (tree_view->priv->search_window, tree_view);
return FALSE;
}
if (validate_row (tree_view, tree, node, &iter, path))
size_changed = TRUE;
}
+
if (tree_view->priv->scroll_to_use_align)
{
gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
}
else
{
- /* FIXME: temporary solution, just validate a complete height
- * and all will be fine...
+ /* two cases:
+ * 1) row not visible
+ * 2) row visible
*/
- area_above = total_height;
- area_below = total_height;
+ gint dy;
+ gint height = MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+
+ dy = _gtk_rbtree_node_find_offset (tree, node);
+
+ if (dy >= tree_view->priv->vadjustment->value &&
+ dy < (tree_view->priv->vadjustment->value
+ + tree_view->priv->vadjustment->page_size))
+ {
+ /* row visible: keep the row at the same position */
+ area_above = dy - tree_view->priv->vadjustment->value;
+ area_below = (tree_view->priv->vadjustment->value +
+ tree_view->priv->vadjustment->page_size)
+ - dy - height;
+ }
+ else
+ {
+ /* row not visible */
+ update_dy = TRUE;
+
+ if (dy >= 0 && dy <= tree_view->priv->vadjustment->page_size)
+ {
+ /* row at the beginning -- fixed */
+ area_above = dy;
+ area_below = tree_view->priv->vadjustment->page_size
+ - area_above - height;
+ }
+ else if (dy >= (tree_view->priv->vadjustment->upper -
+ tree_view->priv->vadjustment->page_size)
+ && dy <= tree_view->priv->vadjustment->upper)
+ {
+ /* row at the end -- fixed */
+ area_above = dy - (tree_view->priv->vadjustment->upper -
+ tree_view->priv->vadjustment->page_size);
+ area_below = tree_view->priv->vadjustment->page_size -
+ area_above - height;
+
+ if (area_below < 0)
+ {
+ area_above += area_below;
+ area_below = 0;
+ }
+ }
+ else
+ {
+ /* row somewhere in the middle, bring it to the top
+ * of the view
+ */
+ area_above = 0;
+ area_below = total_height - height;
+ }
+ }
}
}
else
*/
while (node && area_below > 0)
{
+ gint new_height;
+
if (node->children)
{
GtkTreeIter parent = iter;
}
while (!done);
}
+
+ 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;
+
need_redraw = TRUE;
if (validate_row (tree_view, tree, node, &iter, path))
- size_changed = TRUE;
+ {
+ new_height = GTK_RBNODE_GET_HEIGHT (node);
+ size_changed = TRUE;
+
+ area_below -= new_height - old_height;
+ }
}
- if (node)
- area_below -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+
+ area_below -= MAX (new_height, tree_view->priv->expander_size);
}
gtk_tree_path_free (path);
- /* If we ran out of tree, and have extra area_below left, we need to remove it
- * from the area_above */
+ /* If we ran out of tree, and have extra area_below left, we need to add it
+ * to area_above */
if (area_below > 0)
area_above += area_below;
/* 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;
+
need_redraw = TRUE;
if (validate_row (tree_view, tree, node, &iter, above_path))
- size_changed = TRUE;
+ {
+ new_height = GTK_RBNODE_GET_HEIGHT (node);
+ size_changed = TRUE;
+
+ area_above -= new_height - old_height;
+ }
}
- area_above -= MAX (GTK_RBNODE_GET_HEIGHT (node), tree_view->priv->expander_size);
+ area_above -= MAX (new_height, tree_view->priv->expander_size);
update_dy = TRUE;
}
if (size_changed)
{
GtkRequisition requisition;
+
/* We temporarily guess a size, under the assumption that it will be the
* same when we get our next size_allocate. If we don't do this, we'll be
* in an inconsistent state if we call top_row_to_dy. */
+ gtk_widget_size_request (GTK_WIDGET (tree_view), &requisition);
tree_view->priv->hadjustment->upper = MAX (tree_view->priv->hadjustment->upper, (gfloat)requisition.width);
tree_view->priv->vadjustment->upper = MAX (tree_view->priv->vadjustment->upper, (gfloat)requisition.height);
gtk_adjustment_changed (tree_view->priv->hadjustment);
}
/* if we scroll at all, always update dy and kill the top_row */
- if (tree_view->priv->scroll_to_path)
+ if (tree_view->priv->scroll_to_path &&
+ ! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
{
update_dy = TRUE;
if (tree_view->priv->top_row)
{
dy = 0;
}
+
gtk_adjustment_set_value (tree_view->priv->vadjustment, dy);
need_redraw = TRUE;
}
- if (tree_view->priv->scroll_to_path)
- {
- gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
+ 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 (above_path)
+ gtk_tree_path_free (above_path);
+
+ if (tree_view->priv->scroll_to_column)
+ {
+ tree_view->priv->scroll_to_column = NULL;
+ }
+ if (need_redraw)
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+static void
+initialize_fixed_height_mode (GtkTreeView *tree_view)
+{
+ if (!tree_view->priv->tree)
+ return;
+
+ if (tree_view->priv->fixed_height < 0)
+ {
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+
+ tree = tree_view->priv->tree;
+ node = tree->root;
+
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
- if (above_path)
- gtk_tree_path_free (above_path);
+ validate_row (tree_view, tree, node, &iter, path);
- if (tree_view->priv->scroll_to_column)
- {
- tree_view->priv->scroll_to_column = NULL;
+ gtk_tree_path_free (path);
+
+ tree_view->priv->fixed_height = MAX (GTK_RBNODE_GET_HEIGHT (node),
+ tree_view->priv->expander_size);
}
- if (need_redraw)
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
-}
+ _gtk_rbtree_set_fixed_height (tree_view->priv->tree,
+ tree_view->priv->fixed_height);
+}
/* Our strategy for finding nodes to validate is a little convoluted. We find
* the left-most uninvalidated node. We then try walking right, validating
if (tree_view->priv->tree == NULL)
return FALSE;
+ if (tree_view->priv->fixed_height_mode)
+ {
+ if (tree_view->priv->fixed_height < 0)
+ initialize_fixed_height_mode (tree_view);
+
+ return FALSE;
+ }
+
do
{
if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
path = _gtk_tree_view_find_path (tree_view, tree, node);
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
}
- validated_area = validate_row (tree_view, tree, node, &iter, path) | validated_area;
+
+ validated_area = validate_row (tree_view, tree, node, &iter, path) ||
+ validated_area;
if (!tree_view->priv->fixed_height_check)
{
g_source_remove (tree_view->priv->validate_rows_timer);
tree_view->priv->validate_rows_timer = 0;
}
-
+
return retval;
}
GDK_THREADS_ENTER ();
retval = do_validate_rows (tree_view);
- if (! retval)
- tree_view->priv->validate_rows_timer = 0;
+ if (! retval && tree_view->priv->validate_rows_timer)
+ {
+ g_source_remove (tree_view->priv->validate_rows_timer);
+ tree_view->priv->validate_rows_timer = 0;
+ }
GDK_THREADS_LEAVE ();
return NULL;
}
+typedef struct
+{
+ GtkTreeRowReference *dest_row;
+ gboolean path_down_mode;
+ gboolean empty_view_drop;
+ gboolean drop_append_mode;
+}
+DestRow;
+
+static void
+dest_row_free (gpointer data)
+{
+ DestRow *dr = (DestRow *)data;
+
+ gtk_tree_row_reference_free (dr->dest_row);
+ g_free (dr);
+}
+
static void
set_dest_row (GdkDragContext *context,
GtkTreeModel *model,
- GtkTreePath *dest_row)
+ GtkTreePath *dest_row,
+ gboolean path_down_mode,
+ gboolean empty_view_drop,
+ gboolean drop_append_mode)
{
- g_object_set_data_full (G_OBJECT (context),
- "gtk-tree-view-dest-row",
- dest_row ? gtk_tree_row_reference_new (model, dest_row) : NULL,
- (GDestroyNotify) (dest_row ? gtk_tree_row_reference_free : NULL));
+ DestRow *dr;
+
+ if (!dest_row)
+ {
+ g_object_set_data_full (G_OBJECT (context), "gtk-tree-view-dest-row",
+ NULL, NULL);
+ return;
+ }
+
+ dr = g_new0 (DestRow, 1);
+
+ dr->dest_row = gtk_tree_row_reference_new (model, dest_row);
+ dr->path_down_mode = path_down_mode;
+ 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",
+ dr, (GDestroyNotify) dest_row_free);
}
static GtkTreePath*
-get_dest_row (GdkDragContext *context)
+get_dest_row (GdkDragContext *context,
+ gboolean *path_down_mode)
{
- GtkTreeRowReference *ref =
+ DestRow *dr =
g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
- if (ref)
- return gtk_tree_row_reference_get_path (ref);
+ if (dr)
+ {
+ GtkTreePath *path = NULL;
+
+ if (path_down_mode)
+ *path_down_mode = dr->path_down_mode;
+
+ if (dr->dest_row)
+ path = gtk_tree_row_reference_get_path (dr->dest_row);
+ else if (dr->empty_view_drop)
+ path = gtk_tree_path_new_from_indices (0, -1);
+ else
+ path = NULL;
+
+ if (path && dr->drop_append_mode)
+ gtk_tree_path_next (path);
+
+ return path;
+ }
else
return NULL;
}
{
if (tree_view->priv->scroll_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->scroll_timeout);
+ g_source_remove (tree_view->priv->scroll_timeout);
tree_view->priv->scroll_timeout = 0;
}
}
{
if (tree_view->priv->open_dest_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->open_dest_timeout);
+ g_source_remove (tree_view->priv->open_dest_timeout);
tree_view->priv->open_dest_timeout = 0;
}
}
TreeViewDragInfo *di;
GtkWidget *widget;
GtkTreePath *old_dest_path = NULL;
+ gboolean can_drop = FALSE;
*suggested_action = 0;
*target = GDK_NONE;
di = get_info (tree_view);
- if (di == NULL)
+ if (di == NULL || y - TREE_VIEW_HEADER_HEIGHT (tree_view) < 0)
{
/* someone unset us as a drag dest, note that if
* we return FALSE drag_leave isn't called
&path,
&pos))
{
- /* can't drop here */
+ gint n_children;
+ GtkTreeModel *model;
+
remove_open_timeout (tree_view);
- gtk_tree_view_set_drag_dest_row (GTK_TREE_VIEW (widget),
- NULL,
- GTK_TREE_VIEW_DROP_BEFORE);
+ /* the row got dropped on empty space, let's setup a special case
+ */
if (path)
gtk_tree_path_free (path);
- /* don't propagate to parent though */
- return TRUE;
+ model = gtk_tree_view_get_model (tree_view);
+
+ n_children = gtk_tree_model_iter_n_children (model, NULL);
+ if (n_children)
+ {
+ pos = GTK_TREE_VIEW_DROP_AFTER;
+ path = gtk_tree_path_new_from_indices (n_children - 1, -1);
+ }
+ else
+ {
+ pos = GTK_TREE_VIEW_DROP_BEFORE;
+ path = gtk_tree_path_new_from_indices (0, -1);
+ }
+
+ can_drop = TRUE;
+
+ goto out;
}
g_assert (path);
gtk_tree_path_free (old_dest_path);
if (TRUE /* FIXME if the location droppable predicate */)
+ {
+ can_drop = TRUE;
+ }
+
+out:
+ if (can_drop)
{
GtkWidget *source_widget;
*suggested_action = context->suggested_action;
-
source_widget = gtk_drag_get_source_widget (context);
if (source_widget == widget)
{
/* Default to MOVE, unless the user has
- * pressed ctrl or alt to affect available actions
+ * pressed ctrl or shift to affect available actions
*/
if ((context->actions & GDK_ACTION_MOVE) != 0)
*suggested_action = GDK_ACTION_MOVE;
return TRUE;
}
-static GtkTreePath*
-get_logical_dest_row (GtkTreeView *tree_view)
+static GtkTreePath*
+get_logical_dest_row (GtkTreeView *tree_view,
+ gboolean *path_down_mode,
+ gboolean *drop_append_mode)
{
/* adjust path to point to the row the drop goes in front of */
GtkTreePath *path = NULL;
GtkTreeViewDropPosition pos;
+ g_return_val_if_fail (path_down_mode != NULL, NULL);
+ g_return_val_if_fail (drop_append_mode != NULL, NULL);
+
+ *path_down_mode = FALSE;
+ *drop_append_mode = 0;
+
gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
if (path == NULL)
; /* do nothing */
else if (pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE ||
pos == GTK_TREE_VIEW_DROP_INTO_OR_AFTER)
- {
- /* get first child, drop before it */
- gtk_tree_path_down (path);
- }
+ *path_down_mode = TRUE;
else
{
GtkTreeIter iter;
g_assert (pos == GTK_TREE_VIEW_DROP_AFTER);
- gtk_tree_model_get_iter (model, &iter, path);
-
- if (!gtk_tree_model_iter_next (model, &iter))
- g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
- GINT_TO_POINTER (1));
+ if (!gtk_tree_model_get_iter (model, &iter, path) ||
+ !gtk_tree_model_iter_next (model, &iter))
+ *drop_append_mode = 1;
else
{
- g_object_set_data (G_OBJECT (model), "gtk-tree-model-drop-append",
- NULL);
- gtk_tree_path_next (path);
- }
+ *drop_append_mode = 0;
+ gtk_tree_path_next (path);
+ }
}
return path;
button,
(GdkEvent*)event);
- gtk_drag_set_icon_default (context);
-
- {
- GdkPixmap *row_pix;
-
- row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
- path);
-
- gtk_drag_set_icon_pixmap (context,
- gdk_drawable_get_colormap (row_pix),
- row_pix,
- NULL,
- /* the + 1 is for the black border in the icon */
- tree_view->priv->press_start_x + 1,
- cell_y + 1);
-
- g_object_unref (row_pix);
- }
-
set_source_row (context, model, path);
out:
gtk_tree_view_drag_begin (GtkWidget *widget,
GdkDragContext *context)
{
- /* do nothing */
+ GtkTreeView *tree_view;
+ GtkTreePath *path = NULL;
+ gint cell_x, cell_y;
+ GdkPixmap *row_pix;
+
+ 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))
+ return;
+
+ gtk_tree_view_get_path_at_pos (tree_view,
+ tree_view->priv->press_start_x,
+ tree_view->priv->press_start_y,
+ &path,
+ NULL,
+ &cell_x,
+ &cell_y);
+
+ g_return_if_fail (path != NULL);
+
+ row_pix = gtk_tree_view_create_row_drag_icon (tree_view,
+ path);
+
+ gtk_drag_set_icon_pixmap (context,
+ gdk_drawable_get_colormap (row_pix),
+ row_pix,
+ NULL,
+ /* the + 1 is for the black border in the icon */
+ tree_view->priv->press_start_x + 1,
+ cell_y + 1);
+
+ g_object_unref (row_pix);
+ gtk_tree_path_free (path);
}
static void
gint y,
guint time)
{
+ 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);
- if (path == NULL)
+ /* 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)
{
/* Can't drop here. */
gdk_drag_status (context, 0, time);
pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE))
{
tree_view->priv->open_dest_timeout =
- gtk_timeout_add (500, open_row_timeout, tree_view);
+ g_timeout_add (500, open_row_timeout, tree_view);
}
else if (tree_view->priv->scroll_timeout == 0)
{
tree_view->priv->scroll_timeout =
- gtk_timeout_add (150, scroll_row_timeout, tree_view);
+ g_timeout_add (150, scroll_row_timeout, tree_view);
}
if (target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
GdkAtom target = GDK_NONE;
TreeViewDragInfo *di;
GtkTreeModel *model;
+ gboolean path_down_mode;
+ gboolean drop_append_mode;
tree_view = GTK_TREE_VIEW (widget);
if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
return FALSE;
- path = get_logical_dest_row (tree_view);
+ path = get_logical_dest_row (tree_view, &path_down_mode, &drop_append_mode);
if (target != GDK_NONE && path != NULL)
{
* treat drag data receives as a drop.
*/
set_status_pending (context, 0);
-
- set_dest_row (context, model, path);
+ set_dest_row (context, model, path,
+ path_down_mode, tree_view->priv->empty_view_drop,
+ drop_append_mode);
}
if (path)
GtkTreeView *tree_view;
GtkTreePath *dest_row;
GdkDragAction suggested_action;
+ gboolean path_down_mode;
+ gboolean drop_append_mode;
tree_view = GTK_TREE_VIEW (widget);
* supposed to call drag_status, not actually paste in the
* data.
*/
- path = get_logical_dest_row (tree_view);
+ path = get_logical_dest_row (tree_view, &path_down_mode,
+ &drop_append_mode);
if (path == NULL)
suggested_action = 0;
+ else if (path_down_mode)
+ gtk_tree_path_down (path);
if (suggested_action)
{
if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
path,
selection_data))
- suggested_action = 0;
+ {
+ if (path_down_mode)
+ {
+ path_down_mode = FALSE;
+ gtk_tree_path_up (path);
+
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ path,
+ selection_data))
+ suggested_action = 0;
+ }
+ else
+ suggested_action = 0;
+ }
}
gdk_drag_status (context, suggested_action, time);
return;
}
- dest_row = get_dest_row (context);
+ dest_row = get_dest_row (context, &path_down_mode);
if (dest_row == NULL)
return;
+ if (selection_data->length >= 0)
+ {
+ if (path_down_mode)
+ {
+ gtk_tree_path_down (dest_row);
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ dest_row, selection_data))
+ gtk_tree_path_up (dest_row);
+ }
+ }
+
if (selection_data->length >= 0)
{
if (gtk_tree_drag_dest_drag_data_received (GTK_TREE_DRAG_DEST (model),
(context->action == GDK_ACTION_MOVE),
time);
+ if (gtk_tree_path_get_depth (dest_row) == 1
+ && gtk_tree_path_get_indices (dest_row)[0] == 0)
+ {
+ /* special special case drag to "0", scroll to first item */
+ if (!tree_view->priv->scroll_to_path)
+ gtk_tree_view_scroll_to_cell (tree_view, dest_row, NULL, FALSE, 0.0, 0.0);
+ }
+
gtk_tree_path_free (dest_row);
/* drop dest_row */
- set_dest_row (context, NULL, NULL);
+ set_dest_row (context, NULL, NULL, FALSE, FALSE, FALSE);
}
return FALSE;
}
+static void
+column_sizing_notify (GObject *object,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ GtkTreeViewColumn *c = GTK_TREE_VIEW_COLUMN (object);
+
+ if (gtk_tree_view_column_get_sizing (c) != GTK_TREE_VIEW_COLUMN_FIXED)
+ /* disable fixed height mode */
+ g_object_set (data, "fixed_height_mode", FALSE, NULL);
+}
+
+static void
+gtk_tree_view_set_fixed_height_mode (GtkTreeView *tree_view,
+ gboolean enable)
+{
+ GList *l;
+
+ if (tree_view->priv->fixed_height_mode && enable)
+ return;
+
+ if (!enable)
+ {
+ tree_view->priv->fixed_height_mode = 0;
+ tree_view->priv->fixed_height = -1;
+
+ /* force a revalidation */
+ install_presize_handler (tree_view);
+ return;
+ }
+
+ /* make sure all columns are of type FIXED */
+ for (l = tree_view->priv->columns; l; l = l->next)
+ {
+ GtkTreeViewColumn *c = l->data;
+
+ g_return_if_fail (gtk_tree_view_column_get_sizing (c) == GTK_TREE_VIEW_COLUMN_FIXED);
+ }
+
+ /* yes, we really have to do this is in a separate loop */
+ for (l = tree_view->priv->columns; l; l = l->next)
+ g_signal_connect (l->data, "notify::sizing",
+ G_CALLBACK (column_sizing_notify), tree_view);
+
+ tree_view->priv->fixed_height_mode = 1;
+ tree_view->priv->fixed_height = -1;
+
+ if (!tree_view->priv->tree)
+ return;
+
+ initialize_fixed_height_mode (tree_view);
+}
+
/* Returns TRUE if the focus is within the headers, after the focus operation is
* done
*/
GList *last_column, *first_column;
GList *tmp_list;
+ gboolean rtl;
if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_HEADERS_VISIBLE))
return FALSE;
}
+ 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;
+ }
+
switch (dir)
{
case GTK_DIR_TAB_BACKWARD:
tree_view = GTK_TREE_VIEW (widget);
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
+ gdk_window_set_background (tree_view->priv->bin_window, &widget->style->base[widget->state]);
+ }
+
gtk_widget_style_get (widget,
"expander_size", &tree_view->priv->expander_size,
NULL);
_gtk_tree_view_column_cell_set_dirty (column, TRUE);
}
+ tree_view->priv->fixed_height = -1;
_gtk_rbtree_mark_invalid (tree_view->priv->tree);
gtk_widget_queue_resize (widget);
GtkMovementStep step,
gint count)
{
+ GdkModifierType state;
+
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
g_return_val_if_fail (step == GTK_MOVEMENT_LOGICAL_POSITIONS ||
step == GTK_MOVEMENT_VISUAL_POSITIONS ||
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ if (gtk_get_current_event_state (&state))
+ {
+ if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
+ tree_view->priv->ctrl_pressed = TRUE;
+ if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
+ tree_view->priv->shift_pressed = TRUE;
+ }
+ /* else we assume not pressed */
+
switch (step)
{
/* currently we make no distinction. When we go bi-di, we need to */
g_assert_not_reached ();
}
+ tree_view->priv->ctrl_pressed = FALSE;
+ tree_view->priv->shift_pressed = FALSE;
+
return TRUE;
}
if (tree == NULL)
goto done;
- _gtk_rbtree_node_mark_invalid (tree, node);
- for (list = tree_view->priv->columns; list; list = list->next)
+ if (tree_view->priv->fixed_height_mode
+ && tree_view->priv->fixed_height >= 0)
{
- GtkTreeViewColumn *column;
+ _gtk_rbtree_node_set_height (tree, node, tree_view->priv->fixed_height);
+ }
+ else
+ {
+ _gtk_rbtree_node_mark_invalid (tree, node);
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ GtkTreeViewColumn *column;
- column = list->data;
- if (! column->visible)
- continue;
+ column = list->data;
+ if (! column->visible)
+ continue;
- if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- {
- _gtk_tree_view_column_cell_set_dirty (column, TRUE);
- }
+ if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
+ {
+ _gtk_tree_view_column_cell_set_dirty (column, TRUE);
+ }
+ }
}
done:
- install_presize_handler (tree_view);
+ if (!tree_view->priv->fixed_height_mode)
+ install_presize_handler (tree_view);
if (free_path)
gtk_tree_path_free (path);
}
GtkRBNode *tmpnode = NULL;
gint depth;
gint i = 0;
+ gint height;
gboolean free_path = FALSE;
g_return_if_fail (path != NULL || iter != NULL);
if (tree == NULL)
goto done;
+ if (tree_view->priv->fixed_height_mode
+ && tree_view->priv->fixed_height >= 0)
+ height = tree_view->priv->fixed_height;
+ else
+ height = 0;
+
/* 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, 0, FALSE);
+ _gtk_rbtree_insert_before (tree, tmpnode, height, FALSE);
}
else
{
tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
- _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
- }
+ _gtk_rbtree_insert_after (tree, tmpnode, height, FALSE);
+ }
done:
install_presize_handler (tree_view);
(*((gint *)data))++;
}
+static void
+check_selection_helper (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
+{
+ gint *value = (gint *)data;
+
+ *value = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
+
+ if (node->children && !*value)
+ _gtk_rbtree_traverse (node->children, node->children->root, G_POST_ORDER, check_selection_helper, data);
+}
+
static void
gtk_tree_view_row_deleted (GtkTreeModel *model,
GtkTreePath *path,
GtkRBTree *tree;
GtkRBNode *node;
GList *list;
- gint selection_changed;
+ gint selection_changed = FALSE;
g_return_if_fail (path != NULL);
if (tree == NULL)
return;
- /* Change the selection */
- selection_changed = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
+ /* check if the selection has been changed */
+ _gtk_rbtree_traverse (tree, node, G_POST_ORDER,
+ check_selection_helper, &selection_changed);
for (list = tree_view->priv->columns; list; list = list->next)
if (((GtkTreeViewColumn *)list->data)->visible &&
/* If we have a node expanded/collapsed timeout, remove it */
if (tree_view->priv->expand_collapse_timeout != 0)
{
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ g_source_remove (tree_view->priv->expand_collapse_timeout);
tree_view->priv->expand_collapse_timeout = 0;
/* Reset node */
_gtk_rbtree_remove_node (tree, node);
}
+ if (! gtk_tree_row_reference_valid (tree_view->priv->top_row))
+ {
+ gtk_tree_row_reference_free (tree_view->priv->top_row);
+ tree_view->priv->top_row = NULL;
+ }
+
install_scroll_sync_handler (tree_view);
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
g_signal_emit_by_name (tree_view->priv->selection, "changed");
}
+static void
+cancel_arrow_animation (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->expand_collapse_timeout)
+ {
+ while (do_expand_collapse (tree_view));
+
+ g_source_remove (tree_view->priv->expand_collapse_timeout);
+ tree_view->priv->expand_collapse_timeout = 0;
+ }
+}
static void
gtk_tree_view_rows_reordered (GtkTreeModel *model,
if (tree == NULL)
return;
+ if (tree_view->priv->edited_column)
+ gtk_tree_view_stop_editing (tree_view, TRUE);
+
/* we need to be unprelighted */
ensure_unprelighted (tree_view);
+
+ /* clear the timeout */
+ cancel_arrow_animation (tree_view);
_gtk_rbtree_reorder (tree, new_order, len);
GtkTreeViewColumn *tmp_column = NULL;
gint total_width;
GList *list;
+ gboolean rtl;
if (x1)
*x1 = 0;
if (x2)
*x2 = 0;
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
+
total_width = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
{
tmp_column = list->data;
GtkTreeViewColumn *tmp_column = NULL;
gint total_width;
gboolean indent_expanders;
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
total_width = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
+ for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
+ list;
+ list = (rtl ? list->prev : list->next))
{
tmp_column = list->data;
if (gtk_tree_view_is_expander_column (tree_view, tmp_column))
{
- x_offset = total_width;
+ if (rtl)
+ x_offset = total_width + tmp_column->width - tree_view->priv->expander_size;
+ else
+ x_offset = total_width;
break;
}
NULL);
if (indent_expanders)
- x_offset += tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
-
+ {
+ if (rtl)
+ x_offset -= tree_view->priv->expander_size * _gtk_rbtree_get_depth (tree);
+ 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 = x_offset + tree_view->priv->expander_size + 1;
+ *x2 = *x1 + tree_view->priv->expander_size + 1;
}
else
{
/* return an empty range, the expander column is hidden */
if (x2)
- *x2 = x_offset;
+ *x2 = *x1;
}
}
gboolean recurse)
{
GtkRBNode *temp = NULL;
+ gboolean is_list = GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST);
do
{
gtk_tree_model_ref_node (tree_view->priv->model, iter);
temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
+
+ if (is_list)
+ continue;
+
if (recurse)
{
GtkTreeIter child;
{
if ((temp->flags>K_RBNODE_IS_PARENT) != GTK_RBNODE_IS_PARENT)
temp->flags ^= GTK_RBNODE_IS_PARENT;
- GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
}
}
while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
{
GtkTreePath *path = NULL;
- /* We process updates because we want to clear old selected items when we scroll.
- * if this is removed, we get a "selection streak" at the bottom. */
if (!GTK_WIDGET_REALIZED (tree_view))
return;
if (path)
{
+ /* We process updates because we want to clear old selected items when we scroll.
+ * if this is removed, we get a "selection streak" at the bottom. */
+ gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
gtk_tree_view_scroll_to_cell (tree_view, path, NULL, FALSE, 0.0, 0.0);
gtk_tree_path_free (path);
}
}
else
{
- for (list = tree_view->priv->columns; list; list = list->next)
+ for (list = tree_view->priv->columns;
+ list;
+ list = list->next)
if (((GtkTreeViewColumn *)list->data)->visible)
break;
if (list && list->data == column)
GtkTreeViewColumn *left_column;
GtkTreeViewColumn *cur_column = NULL;
GtkTreeViewColumnReorder *reorder;
-
+ gboolean rtl;
GList *tmp_list;
gint left;
* are available.
*/
left_column = NULL;
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
/* First, identify all possible drop spots */
- tmp_list = tree_view->priv->columns;
+ if (rtl)
+ tmp_list = g_list_last (tree_view->priv->columns);
+ else
+ tmp_list = g_list_first (tree_view->priv->columns);
while (tmp_list)
{
- g_assert (tmp_list);
-
cur_column = GTK_TREE_VIEW_COLUMN (tmp_list->data);
- tmp_list = tmp_list->next;
+ tmp_list = rtl?g_list_previous (tmp_list):g_list_next (tmp_list);
if (cur_column->visible == FALSE)
continue;
GtkTreeIter iter;
GList *list;
gboolean found_column = FALSE;
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
return;
}
loop_end:
if (count == 1)
- list = list->next;
+ list = rtl ? list->prev : list->next;
else
- list = list->prev;
+ list = rtl ? list->next : list->prev;
}
if (found_column)
gtk_tree_path_free (path);
}
-static void
+static gboolean
gtk_tree_view_real_select_all (GtkTreeView *tree_view)
{
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
- return;
+ return FALSE;
+
gtk_tree_selection_select_all (tree_view->priv->selection);
+
+ return TRUE;
}
-static void
+static gboolean
gtk_tree_view_real_unselect_all (GtkTreeView *tree_view)
{
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
+
+ if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+ return FALSE;
- if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
- return;
gtk_tree_selection_unselect_all (tree_view->priv->selection);
+
+ return TRUE;
}
-static void
+static gboolean
gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view,
gboolean start_editing)
{
GtkRBTree *cursor_tree = NULL;
GtkRBNode *cursor_node = NULL;
GtkTreePath *cursor_path = NULL;
- GdkModifierType state = 0;
- cursor_path = NULL;
+ GtkTreeSelectMode mode = 0;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
if (tree_view->priv->cursor)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
if (cursor_path == NULL)
- return;
+ return FALSE;
_gtk_tree_view_find_node (tree_view, cursor_path,
&cursor_tree, &cursor_node);
if (cursor_tree == NULL)
{
gtk_tree_path_free (cursor_path);
- return;
+ return FALSE;
}
- gtk_get_current_event_state (&state);
-
- if (! (state & GDK_SHIFT_MASK) &&
- start_editing &&
+ if (!tree_view->priv->shift_pressed && start_editing &&
tree_view->priv->focus_column)
{
if (gtk_tree_view_start_editing (tree_view, cursor_path))
{
gtk_tree_path_free (cursor_path);
- return;
+ return TRUE;
}
}
+
+ if (tree_view->priv->ctrl_pressed)
+ mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+ if (tree_view->priv->shift_pressed)
+ mode |= GTK_TREE_SELECT_MODE_EXTEND;
+
_gtk_tree_selection_internal_select_node (tree_view->priv->selection,
cursor_node,
cursor_tree,
cursor_path,
- state,
+ mode,
FALSE);
gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
_gtk_tree_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
- if (! (state & GDK_SHIFT_MASK))
- gtk_tree_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column);
+ if (!tree_view->priv->shift_pressed)
+ gtk_tree_view_row_activated (tree_view, cursor_path,
+ tree_view->priv->focus_column);
gtk_tree_path_free (cursor_path);
+
+ return TRUE;
}
-static void
+static gboolean
gtk_tree_view_real_toggle_cursor_row (GtkTreeView *tree_view)
{
GtkRBTree *cursor_tree = NULL;
GtkTreePath *cursor_path = NULL;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
cursor_path = NULL;
if (tree_view->priv->cursor)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
if (cursor_path == NULL)
- return;
+ return FALSE;
_gtk_tree_view_find_node (tree_view, cursor_path,
&cursor_tree, &cursor_node);
if (cursor_tree == NULL)
{
gtk_tree_path_free (cursor_path);
- return;
+ return FALSE;
}
_gtk_tree_selection_internal_select_node (tree_view->priv->selection,
cursor_node,
cursor_tree,
cursor_path,
- GDK_CONTROL_MASK,
+ GTK_TREE_SELECT_MODE_TOGGLE,
FALSE);
gtk_tree_view_clamp_node_visible (tree_view, cursor_tree, cursor_node);
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
gtk_tree_path_free (cursor_path);
-}
-
+ return TRUE;
+}
-static void
+static gboolean
gtk_tree_view_real_expand_collapse_cursor_row (GtkTreeView *tree_view,
gboolean logical,
gboolean expand,
GtkRBNode *node;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
cursor_path = NULL;
if (tree_view->priv->cursor)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
if (cursor_path == NULL)
- return;
+ return FALSE;
if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
- return;
+ return FALSE;
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+ if (!logical
+ && gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL)
+ expand = !expand;
+
if (expand)
gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
else
gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
gtk_tree_path_free (cursor_path);
+
+ return TRUE;
}
-static void
+static gboolean
gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
{
GtkRBTree *cursor_tree = NULL;
GtkTreePath *cursor_path = NULL;
if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
+ return FALSE;
cursor_path = NULL;
if (tree_view->priv->cursor)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
if (cursor_path == NULL)
- return;
+ return FALSE;
_gtk_tree_view_find_node (tree_view, cursor_path,
&cursor_tree, &cursor_node);
if (cursor_tree == NULL)
{
gtk_tree_path_free (cursor_path);
- return;
+ return FALSE;
}
if (cursor_tree->parent_node)
cursor_node,
cursor_tree,
cursor_path,
- 0,
+ 0,
FALSE);
}
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
gtk_tree_path_free (cursor_path);
+
+ return TRUE;
}
/* Cut and paste from gtkwindow.c */
}
static void
-gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
+gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
{
- GtkWidget *window;
- GtkWidget *entry;
- GtkWidget *search_dialog;
-
- if (! GTK_WIDGET_HAS_FOCUS (tree_view))
- return;
-
- if (tree_view->priv->enable_search == FALSE ||
- tree_view->priv->search_column < 0)
- return;
-
- search_dialog = g_object_get_data (G_OBJECT (tree_view),
- GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
- if (search_dialog)
+ if (tree_view->priv->search_window != NULL)
return;
- /* set up window */
- window = gtk_window_new (GTK_WINDOW_POPUP);
- gtk_window_set_title (GTK_WINDOW (window), "search dialog");
- gtk_container_set_border_width (GTK_CONTAINER (window), 3);
- gtk_window_set_modal (GTK_WINDOW (window), TRUE);
- g_signal_connect (window, "delete_event",
+ tree_view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_container_set_border_width (GTK_CONTAINER (tree_view->priv->search_window), 3);
+ gtk_window_set_modal (GTK_WINDOW (tree_view->priv->search_window), TRUE);
+ g_signal_connect (tree_view->priv->search_window, "delete_event",
G_CALLBACK (gtk_tree_view_search_delete_event),
tree_view);
- g_signal_connect (window, "key_press_event",
+ g_signal_connect (tree_view->priv->search_window, "key_press_event",
G_CALLBACK (gtk_tree_view_search_key_press_event),
tree_view);
- g_signal_connect (window, "button_press_event",
+ g_signal_connect (tree_view->priv->search_window, "button_press_event",
G_CALLBACK (gtk_tree_view_search_button_press_event),
tree_view);
/* add entry */
- entry = gtk_entry_new ();
- gtk_widget_show (entry);
- g_signal_connect (entry, "changed",
+ tree_view->priv->search_entry = gtk_entry_new ();
+ gtk_widget_show (tree_view->priv->search_entry);
+ g_signal_connect (tree_view->priv->search_entry, "changed",
G_CALLBACK (gtk_tree_view_search_init),
tree_view);
- g_signal_connect (entry, "populate_popup",
+ g_signal_connect (tree_view->priv->search_entry, "populate_popup",
G_CALLBACK (gtk_tree_view_search_disable_popdown),
tree_view);
- gtk_container_add (GTK_CONTAINER (window), entry);
+ gtk_container_add (GTK_CONTAINER (tree_view->priv->search_window),
+ tree_view->priv->search_entry);
+}
- /* done, show it */
- tree_view->priv->search_dialog_position_func (tree_view, window);
- gtk_widget_show_all (window);
- gtk_widget_grab_focus (entry);
+static gboolean
+gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
+{
+ if (! GTK_WIDGET_HAS_FOCUS (tree_view))
+ return FALSE;
- /* send focus-in event */
- send_focus_change (entry, TRUE);
+ if (tree_view->priv->enable_search == FALSE ||
+ tree_view->priv->search_column < 0)
+ return FALSE;
+
+ gtk_tree_view_ensure_interactive_directory (tree_view);
+ gtk_entry_set_text (GTK_ENTRY (tree_view->priv->search_entry), "");
- /* position window */
+ /* done, show it */
+ tree_view->priv->search_dialog_position_func (tree_view, tree_view->priv->search_window);
+ gtk_widget_show (tree_view->priv->search_window);
+ gtk_widget_grab_focus (tree_view->priv->search_entry);
- /* yes, we point to the entry's private text thing here, a bit evil */
- g_object_set_data (G_OBJECT (window), "gtk-tree-view-text",
- (gchar *) gtk_entry_get_text (GTK_ENTRY (entry)));
- g_object_set_data (G_OBJECT (tree_view),
- GTK_TREE_VIEW_SEARCH_DIALOG_KEY, window);
+ /* send focus-in event */
+ send_focus_change (tree_view->priv->search_entry, TRUE);
/* search first matching iter */
- gtk_tree_view_search_init (entry, tree_view);
+ gtk_tree_view_search_init (tree_view->priv->search_entry, tree_view);
+
+ return TRUE;
}
/* this function returns the new width of the column being resized given
{
GtkTreeViewColumn *column;
gint width;
+ gboolean rtl;
/* first translate the x position from widget->window
* to clist->clist_window
*/
-
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
column = g_list_nth (tree_view->priv->columns, i)->data;
- width = *x - column->button->allocation.x;
-
+ width = rtl ? (column->button->allocation.x + column->button->allocation.width - *x) : (*x - column->button->allocation.x);
+
/* Clamp down the value */
if (column->min_width == -1)
width = MAX (column->button->requisition.width,
width);
if (column->max_width != -1)
width = MIN (width, column->max_width != -1);
- *x = column->button->allocation.x + width;
+ *x = rtl ? (column->button->allocation.x + column->button->allocation.width - width) : (column->button->allocation.x + width);
+
return width;
}
- tree_view->priv->hadjustment->value,
0);
dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
+ if (dy && tree_view->priv->edited_column)
+ {
+ if (GTK_IS_WIDGET (tree_view->priv->edited_column->editable_widget))
+ GTK_WIDGET (tree_view->priv->edited_column->editable_widget)->allocation.y += dy;
+ }
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);
- gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
- gdk_window_process_updates (tree_view->priv->header_window, TRUE);
}
}
tree_view->priv->cursor = NULL;
gtk_tree_row_reference_free (tree_view->priv->anchor);
tree_view->priv->anchor = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->top_row);
+ tree_view->priv->top_row = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->last_button_press);
+ tree_view->priv->last_button_press = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->last_button_press_2);
+ tree_view->priv->last_button_press_2 = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->scroll_to_path);
+ tree_view->priv->scroll_to_path = NULL;
+
+ tree_view->priv->scroll_to_column = NULL;
g_object_unref (tree_view->priv->model);
+
tree_view->priv->search_column = -1;
- GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
tree_view->priv->fixed_height_check = 0;
+ tree_view->priv->fixed_height = -1;
+ tree_view->priv->dy = tree_view->priv->top_row_dy = 0;
}
tree_view->priv->model = model;
gint i;
GtkTreePath *path;
GtkTreeIter iter;
-
+ GtkTreeModelFlags flags;
if (tree_view->priv->search_column == -1)
{
for (i = 0; i < gtk_tree_model_get_n_columns (model); i++)
{
- if (gtk_tree_model_get_column_type (model, i) == G_TYPE_STRING)
+ GType type = gtk_tree_model_get_column_type (model, i);
+
+ if (g_value_type_transformable (type, G_TYPE_STRING))
{
tree_view->priv->search_column = i;
break;
}
}
}
+
g_object_ref (tree_view->priv->model);
g_signal_connect (tree_view->priv->model,
"row_changed",
G_CALLBACK (gtk_tree_view_rows_reordered),
tree_view);
+ flags = gtk_tree_model_get_flags (tree_view->priv->model);
+ if ((flags & GTK_TREE_MODEL_LIST_ONLY) == GTK_TREE_MODEL_LIST_ONLY)
+ GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
+ else
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_IS_LIST);
+
path = gtk_tree_path_new_first ();
if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
{
* @tree_view: A #GtkTreeView.
* @column: The #GtkTreeViewColumn to add.
*
- * Appends @column to the list of columns.
+ * Appends @column to the list of columns. If @tree_view has "fixed_height"
+ * mode enbabled, then @column must have its "sizing" property set to be
+ * GTK_TREE_VIEW_COLUMN_FIXED.
*
* Return value: The number of columns in @tree_view after appending.
**/
g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (column), -1);
g_return_val_if_fail (column->tree_view == GTK_WIDGET (tree_view), -1);
- _gtk_tree_view_column_unset_tree_view (column);
-
if (tree_view->priv->focus_column == column)
tree_view->priv->focus_column = NULL;
+ if (tree_view->priv->edited_column == column)
+ {
+ gtk_tree_view_stop_editing (tree_view, TRUE);
+
+ /* no need to, but just to be sure ... */
+ tree_view->priv->edited_column = NULL;
+ }
+
+ g_signal_handlers_disconnect_by_func (column,
+ G_CALLBACK (column_sizing_notify),
+ tree_view);
+
+ _gtk_tree_view_column_unset_tree_view (column);
+
tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
tree_view->priv->n_columns--;
* @position: The position to insert @column in.
*
* This inserts the @column into the @tree_view at @position. If @position is
- * -1, then the column is inserted at the end.
+ * -1, then the column is inserted at the end. If @tree_view has
+ * "fixed_height" mode enabled, then @column must 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_COLUMN (column), -1);
g_return_val_if_fail (column->tree_view == NULL, -1);
+ if (tree_view->priv->fixed_height_mode)
+ 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));
gdk_window_show (tree_view->priv->header_window);
}
+ g_signal_connect (column, "notify::sizing",
+ G_CALLBACK (column_sizing_notify), tree_view);
+
tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
column, position);
tree_view->priv->n_columns++;
*
* 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.
+ * the end. The column is initialized with the attributes given. If @tree_view
+ * has "fixed_height" mode enabled, then @column must have its sizing
+ * property set to be GTK_TREE_VIEW_COLUMN_FIXED.
*
* Return value: The number of columns in @tree_view after insertion.
**/
* 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
+ * "sizing" property set to be GTK_TREE_VIEW_COLUMN_FIXED.
*
* Return value: number of columns in the tree view post-insert
**/
*
* If @use_align is %FALSE, then the alignment arguments are ignored, and the
* tree does the minimum amount of work to scroll the cell onto the screen.
- * This means that the cell will be scrolled to the edge closest to it's current
+ * This means that the cell will be scrolled to the edge closest to its current
* position. If the cell is currently visible on the screen, nothing is done.
*
* This function only works if the model is set, and @path is a valid row on the
}
+static void
+gtk_tree_view_expand_all_emission_helper (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
+{
+ GtkTreeView *tree_view = data;
+
+ if ((node->flags & GTK_RBNODE_IS_PARENT) == GTK_RBNODE_IS_PARENT &&
+ node->children)
+ {
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+
+ g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
+
+ gtk_tree_path_free (path);
+ }
+
+ if (node->children)
+ _gtk_rbtree_traverse (node->children,
+ node->children->root,
+ G_PRE_ORDER,
+ gtk_tree_view_expand_all_emission_helper,
+ tree_view);
+}
+
static void
gtk_tree_view_expand_all_helper (GtkRBTree *tree,
GtkRBNode *node,
&child,
gtk_tree_path_get_depth (path) + 1,
TRUE);
+
+ g_signal_emit (tree_view, tree_view_signals[ROW_EXPANDED], 0, &iter, path);
+ _gtk_rbtree_traverse (node->children,
+ node->children->root,
+ G_PRE_ORDER,
+ gtk_tree_view_expand_all_emission_helper,
+ tree_view);
gtk_tree_path_free (path);
}
}
static gboolean
expand_collapse_timeout (gpointer data)
{
- GtkTreeView *tree_view = data;
+ gboolean retval;
+
+ GDK_THREADS_ENTER ();
+
+ retval = do_expand_collapse (data);
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+static gboolean
+do_expand_collapse (GtkTreeView *tree_view)
+{
GtkRBNode *node;
GtkRBTree *tree;
gboolean expanding;
gboolean redraw;
- GDK_THREADS_ENTER ();
-
redraw = FALSE;
expanding = TRUE;
{
gtk_tree_view_queue_draw_arrow (tree_view, tree, node, NULL);
- GDK_THREADS_LEAVE ();
-
return TRUE;
}
- GDK_THREADS_LEAVE ();
-
return FALSE;
}
*
* Expands the row at @path. This will also expand all parent rows of
* @path as necessary.
+ *
+ * Since: 2.2
**/
void
gtk_tree_view_expand_to_path (GtkTreeView *tree_view,
if (tree_view->priv->expand_collapse_timeout)
{
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ g_source_remove (tree_view->priv->expand_collapse_timeout);
tree_view->priv->expand_collapse_timeout = 0;
}
if (animate)
{
- tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
tree_view->priv->expanded_collapsed_node = node;
tree_view->priv->expanded_collapsed_tree = tree;
gint x, y;
GList *list;
GdkDisplay *display;
+ GdkWindow *child, *parent;
if (node->children == NULL)
return FALSE;
if (tree_view->priv->expand_collapse_timeout)
{
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ g_source_remove (tree_view->priv->expand_collapse_timeout);
tree_view->priv->expand_collapse_timeout = 0;
}
if (animate)
{
- tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expand_collapse_timeout = g_timeout_add (50, expand_collapse_timeout, tree_view);
tree_view->priv->expanded_collapsed_node = node;
tree_view->priv->expanded_collapsed_tree = tree;
g_signal_emit (tree_view, tree_view_signals[ROW_COLLAPSED], 0, &iter, path);
- /* 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);
- if (gdk_display_get_window_at_pointer (display, &x, &y) == tree_view->priv->bin_window)
+ if (GTK_WIDGET_MAPPED (tree_view))
{
- GdkEventMotion event;
- event.window = tree_view->priv->bin_window;
- event.x = x;
- event.y = y;
+ /* 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);
+
+ if (gdk_window_get_pointer (parent, &x, &y, NULL) == child)
+ {
+ GdkEventMotion event;
+ gint child_x, child_y;
- /* despite the fact this isn't a real event, I'm almost positive it will
- * never trigger a drag event. maybe_drag is the only function that uses
- * more than just event.x and event.y. */
- gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
+ gdk_window_get_position (child, &child_x, &child_y);
+
+ event.window = tree_view->priv->bin_window;
+ event.x = x - child_x;
+ event.y = y - child_y;
+
+ /* despite the fact this isn't a real event, I'm almost positive it will
+ * never trigger a drag event. maybe_drag is the only function that uses
+ * more than just event.x and event.y. */
+ gtk_tree_view_motion_bin_window (GTK_WIDGET (tree_view), &event);
+ }
}
+
return TRUE;
}
return (node->children != NULL);
}
-static GtkTargetEntry row_targets[] = {
+static const GtkTargetEntry row_targets[] = {
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
};
* #GtkTreeStore and #GtkListStore support these. If @reorderable is %TRUE, then
* the user can reorder the model by dragging and dropping rows. The
* developer can listen to these changes by connecting to the model's
- * signals.
+ * row_inserted and row_deleted signals.
*
* This function does not give you any degree of control over the order -- any
- * reorderering is allowed. If more control is needed, you should probably
+ * reordering is allowed. If more control is needed, you should probably
* handle drag and drop manually.
**/
void
{
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
- GdkModifierType state = 0;
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
{
}
gtk_tree_row_reference_free (tree_view->priv->cursor);
- gtk_get_current_event_state (&state);
tree_view->priv->cursor = gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
tree_view->priv->model,
_gtk_tree_view_find_node (tree_view, path, &tree, &node);
if (tree != NULL)
{
- if (clear_and_select && !((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK))
- _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
- node, tree, path,
- state, FALSE);
+ GtkRBTree *new_tree = NULL;
+ GtkRBNode *new_node = NULL;
+
+ if (clear_and_select && !tree_view->priv->ctrl_pressed)
+ {
+ GtkTreeSelectMode mode = 0;
+
+ if (tree_view->priv->ctrl_pressed)
+ mode |= GTK_TREE_SELECT_MODE_TOGGLE;
+ if (tree_view->priv->shift_pressed)
+ mode |= GTK_TREE_SELECT_MODE_EXTEND;
+
+ _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
+ node, tree, path, mode,
+ FALSE);
+ }
+
+ /* We have to re-find tree and node here again, somebody might have
+ * cleared the node or the whole tree in the GtkTreeSelection::changed
+ * callback. If the nodes differ we bail out here.
+ */
+ _gtk_tree_view_find_node (tree_view, path, &new_tree, &new_node);
+
+ if (tree != new_tree || node != new_node)
+ return;
+
if (clamp_node)
{
gtk_tree_view_clamp_node_visible (tree_view, tree, node);
* Fills in @path and @focus_column with the current path and focus column. If
* the cursor isn't currently set, then *@path will be %NULL. If no column
* currently has focus, then *@focus_column will be %NULL.
+ *
+ * The returned #GtkTreePath must be freed with gtk_tree_path_free() when
+ * you are done with it.
**/
void
gtk_tree_view_get_cursor (GtkTreeView *tree_view,
*
* Sets the current keyboard focus to be at @path, and selects it. This is
* useful when you want to focus the user's attention on a particular row. If
- * @column is not %NULL, then focus is given to the column specified by it.
- * Additionally, if @column is specified, and @start_editing is %TRUE, then
- * editing should be started in the specified cell. This function is often
- * followed by @gtk_widget_grab_focus (@tree_view) in order to give keyboard
- * focus to the widget. Please note that editing can only happen when the
- * widget is realized.
+ * @focus_column is not %NULL, then focus is given to the column specified by
+ * it. Additionally, if @focus_column is specified, and @start_editing is
+ * %TRUE, then editing should be started in the specified cell.
+ * This function is often followed by @gtk_widget_grab_focus (@tree_view)
+ * in order to give keyboard focus to the widget. Please note that editing
+ * can only happen when the widget is realized.
**/
void
gtk_tree_view_set_cursor (GtkTreeView *tree_view,
* @gtk_widget_grab_focus (@tree_view) in order to give keyboard focus to the
* widget. Please note that editing can only happen when the widget is
* realized.
+ *
+ * Since: 2.2
**/
void
gtk_tree_view_set_cursor_on_cell (GtkTreeView *tree_view,
g_return_if_fail (GTK_IS_CELL_RENDERER (focus_cell));
}
+ /* cancel the current editing, if it exists */
+ if (tree_view->priv->edited_column &&
+ tree_view->priv->edited_column->editable_widget)
+ gtk_tree_view_stop_editing (tree_view, TRUE);
+
gtk_tree_view_real_set_cursor (tree_view, path, TRUE, TRUE);
if (focus_column && focus_column->visible)
if (tree_view->priv->tree == NULL)
return FALSE;
- if (x > tree_view->priv->hadjustment->page_size)
+ if (x > tree_view->priv->hadjustment->upper)
return FALSE;
if (x < 0 || y < 0)
remaining_x -= tmp_column->width;
}
+ /* If found is FALSE and there is a last_column, then it the remainder
+ * space is in that area
+ */
if (!found)
{
- if (column)
- *column = last_column;
-
- if (cell_x)
- *cell_x = last_column->width + remaining_x;
- }
+ if (last_column)
+ {
+ if (column)
+ *column = last_column;
+
+ if (cell_x)
+ *cell_x = last_column->width + remaining_x;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
}
y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
* gtk_tree_view_get_cell_area:
* @tree_view: a #GtkTreeView
* @path: a #GtkTreePath for the row, or %NULL to get only horizontal coordinates
- * @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
+ * @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
}
}
+/**
+ * gtk_tree_view_enable_model_drag_source:
+ * @tree_view: a #GtkTreeView
+ * @start_button_mask: Mask of allowed buttons to start drag
+ * @targets: the table of targets that the drag will support
+ * @n_targets: the number of items in @targets
+ * @actions: the bitmask of possible actions for a drag from this
+ * widget
+ *
+ * Turns @tree_view into a drag source for automatic DND.
+ **/
void
gtk_tree_view_enable_model_drag_source (GtkTreeView *tree_view,
GdkModifierType start_button_mask,
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ gtk_drag_source_set (GTK_WIDGET (tree_view),
+ 0,
+ NULL,
+ 0,
+ actions);
+
di = ensure_info (tree_view);
clear_source_info (di);
unset_reorderable (tree_view);
}
+/**
+ * gtk_tree_view_enable_model_drag_dest:
+ * @tree_view: a #GtkTreeView
+ * @targets: the table of targets that the drag will support
+ * @n_targets: the number of items in @targets
+ * @actions: the bitmask of possible actions for a drag from this
+ * widget
+ *
+ * Turns @tree_view into a drop destination for automatic DND.
+ **/
void
gtk_tree_view_enable_model_drag_dest (GtkTreeView *tree_view,
const GtkTargetEntry *targets,
unset_reorderable (tree_view);
}
+/**
+ * gtk_tree_view_unset_rows_drag_source:
+ * @tree_view: a #GtkTreeView
+ *
+ * Undoes the effect of gtk_tree_view_enable_model_drag_source().
+ **/
void
gtk_tree_view_unset_rows_drag_source (GtkTreeView *tree_view)
{
{
if (di->source_set)
{
+ gtk_drag_source_unset (GTK_WIDGET (tree_view));
clear_source_info (di);
di->source_set = FALSE;
}
unset_reorderable (tree_view);
}
+/**
+ * gtk_tree_view_unset_rows_drag_dest:
+ * @tree_view: a #GtkTreeView
+ *
+ * Undoes the effect of gtk_tree_view_enable_model_drag_dest().
+ **/
void
gtk_tree_view_unset_rows_drag_dest (GtkTreeView *tree_view)
{
unset_reorderable (tree_view);
}
+/**
+ * gtk_tree_view_set_drag_dest_row:
+ * @tree_view: a #GtkTreeView
+ * @path: The path of the row to highlight, or %NULL.
+ * @pos: Specifies whether to drop before, after or into the row
+ *
+ * Sets the row that is highlighted for feedback.
+ **/
void
gtk_tree_view_set_drag_dest_row (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewDropPosition pos)
{
GtkTreePath *current_dest;
+
/* Note; this function is exported to allow a custom DND
* implementation, so it can't touch TreeViewDragInfo
*/
current_dest = NULL;
if (tree_view->priv->drag_dest_row)
- current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+ {
+ current_dest = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
+ gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+ }
- if (tree_view->priv->drag_dest_row)
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+ /* special case a drop on an empty model */
+ tree_view->priv->empty_view_drop = 0;
+
+ if (pos == GTK_TREE_VIEW_DROP_BEFORE && path
+ && gtk_tree_path_get_depth (path) == 1
+ && gtk_tree_path_get_indices (path)[0] == 0)
+ {
+ gint n_children;
+
+ n_children = gtk_tree_model_iter_n_children (tree_view->priv->model,
+ NULL);
+
+ if (!n_children)
+ tree_view->priv->empty_view_drop = 1;
+ }
tree_view->priv->drag_dest_pos = pos;
}
}
+/**
+ * gtk_tree_view_get_drag_dest_row:
+ * @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
+ *
+ * Gets information about the row that is highlighted for feedback.
+ **/
void
gtk_tree_view_get_drag_dest_row (GtkTreeView *tree_view,
GtkTreePath **path,
if (tree_view->priv->drag_dest_row)
*path = gtk_tree_row_reference_get_path (tree_view->priv->drag_dest_row);
else
- *path = NULL;
+ {
+ if (tree_view->priv->empty_view_drop)
+ *path = gtk_tree_path_new_from_indices (0, -1);
+ else
+ *path = NULL;
+ }
}
if (pos)
*pos = tree_view->priv->drag_dest_pos;
}
+/**
+ * gtk_tree_view_get_dest_row_at_pos:
+ * @tree_view: a #GtkTreeView
+ * @drag_x: the position to determine the destination row for
+ * @drag_y: the position to determine the destination row for
+ * @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.
+ *
+ * Return value: whether there is a row at the given postiion,
+ **/
gboolean
gtk_tree_view_get_dest_row_at_pos (GtkTreeView *tree_view,
gint drag_x,
* @search_user_data: user data to pass to @search_equal_func, or %NULL
* @search_destroy: Destroy notifier for @search_user_data, or %NULL
*
- * Sets the compare function for the interactive search capabilities.
+ * Sets the compare function for the interactive search capabilities; note
+ * that somewhat like strcmp() returning 0 for equality
+ * #GtkTreeViewSearchEqualFunc returns %FALSE on matches.
**/
void
gtk_tree_view_set_search_equal_func (GtkTreeView *tree_view,
}
static void
-gtk_tree_view_search_dialog_destroy (GtkWidget *search_dialog,
+gtk_tree_view_search_dialog_hide (GtkWidget *search_dialog,
GtkTreeView *tree_view)
{
- GtkEntry *entry = (GtkEntry *)(gtk_container_get_children (GTK_CONTAINER (search_dialog)))->data;
- gint *selected_iter;
-
if (tree_view->priv->disable_popdown)
return;
- if (entry)
- {
- /* send focus-in event */
- send_focus_change (GTK_WIDGET (entry), FALSE);
- }
-
- /* remove data from tree_view */
- g_object_set_data (G_OBJECT (tree_view), GTK_TREE_VIEW_SEARCH_DIALOG_KEY,
- NULL);
-
- selected_iter = g_object_get_data (G_OBJECT (search_dialog),
- "gtk-tree-view-selected-iter");
- if (selected_iter)
- g_free (selected_iter);
- g_object_set_data (G_OBJECT (search_dialog), "gtk-tree-view-selected-iter",
- NULL);
-
- gtk_widget_destroy (search_dialog);
+ /* send focus-in event */
+ send_focus_change (GTK_WIDGET (tree_view->priv->search_entry), FALSE);
+ gtk_widget_hide (search_dialog);
}
static void
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- gtk_tree_view_search_dialog_destroy (widget, tree_view);
+ gtk_tree_view_search_dialog_hide (widget, tree_view);
return TRUE;
}
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- gtk_tree_view_search_dialog_destroy (widget, tree_view);
+ gtk_tree_view_search_dialog_hide (widget, tree_view);
return TRUE;
}
event->keyval == GDK_Return ||
event->keyval == GDK_Tab)
{
- gtk_tree_view_search_dialog_destroy (widget, tree_view);
+ gtk_tree_view_search_dialog_hide (widget, tree_view);
return TRUE;
}
/* select previous matching iter */
- if (event->keyval == GDK_Up)
+ if (event->keyval == GDK_Up || event->keyval == GDK_KP_Up)
{
gtk_tree_view_search_move (widget, tree_view, TRUE);
return TRUE;
}
/* select next matching iter */
- if (event->keyval == GDK_Down)
+ if (event->keyval == GDK_Down || event->keyval == GDK_KP_Down)
{
gtk_tree_view_search_move (widget, tree_view, FALSE);
return TRUE;
gboolean up)
{
gboolean ret;
- gint *selected_iter;
gint len;
gint count = 0;
- gchar *text;
+ const gchar *text;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreeSelection *selection;
- text = g_object_get_data (G_OBJECT (window), "gtk-tree-view-text");
- selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
+ text = gtk_entry_get_text (GTK_ENTRY (tree_view->priv->search_entry));
g_return_if_fail (text != NULL);
- if (!selected_iter || (up && *selected_iter == 1))
+ if (up && tree_view->priv->selected_iter == 1)
return;
len = strlen (text);
gtk_tree_model_get_iter_first (model, &iter);
ret = gtk_tree_view_search_iter (model, selection, &iter, text,
- &count, up?((*selected_iter) - 1):((*selected_iter + 1)));
+ &count, up?((tree_view->priv->selected_iter) - 1):((tree_view->priv->selected_iter + 1)));
if (ret)
{
/* found */
- *selected_iter += up?(-1):(1);
+ tree_view->priv->selected_iter += up?(-1):(1);
}
else
{
gtk_tree_model_get_iter_first (model, &iter);
gtk_tree_view_search_iter (model, selection,
&iter, text,
- &count, *selected_iter);
+ &count, tree_view->priv->selected_iter);
}
}
gpointer search_data)
{
gboolean retval = TRUE;
+ const gchar *str;
gchar *normalized_string;
gchar *normalized_key;
- gchar *case_normalized_string;
- gchar *case_normalized_key;
+ gchar *case_normalized_string = NULL;
+ gchar *case_normalized_key = NULL;
GValue value = {0,};
- gint key_len;
+ GValue transformed = {0,};
gtk_tree_model_get_value (model, iter, column, &value);
- normalized_string = g_utf8_normalize (g_value_get_string (&value), -1, G_NORMALIZE_ALL);
- normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
- case_normalized_string = g_utf8_casefold (normalized_string, -1);
- case_normalized_key = g_utf8_casefold (normalized_key, -1);
- key_len = strlen (case_normalized_key);
+ g_value_init (&transformed, G_TYPE_STRING);
- if (!strncmp (case_normalized_key, case_normalized_string, key_len))
- retval = FALSE;
+ if (!g_value_transform (&value, &transformed))
+ {
+ g_value_unset (&value);
+ return TRUE;
+ }
g_value_unset (&value);
+
+ str = g_value_get_string (&transformed);
+ if (!str)
+ {
+ g_value_unset (&transformed);
+ return TRUE;
+ }
+
+ normalized_string = g_utf8_normalize (str, -1, G_NORMALIZE_ALL);
+ normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
+
+ if (normalized_string && normalized_key)
+ {
+ case_normalized_string = g_utf8_casefold (normalized_string, -1);
+ case_normalized_key = g_utf8_casefold (normalized_key, -1);
+
+ if (strstr (case_normalized_string, case_normalized_key))
+ retval = FALSE;
+ }
+
+ g_value_unset (&transformed);
g_free (normalized_key);
g_free (normalized_string);
g_free (case_normalized_key);
GtkTreeView *tree_view)
{
gint ret;
- gint *selected_iter;
gint len;
gint count = 0;
const gchar *text;
/* search */
gtk_tree_selection_unselect_all (selection);
- selected_iter = g_object_get_data (G_OBJECT (window), "gtk-tree-view-selected-iter");
- if (selected_iter)
- g_free (selected_iter);
- g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter", NULL);
if (len < 1)
return;
&count, 1);
if (ret)
- {
- selected_iter = g_malloc (sizeof (int));
- *selected_iter = 1;
- g_object_set_data (G_OBJECT (window), "gtk-tree-view-selected-iter",
- selected_iter);
- }
+ tree_view->priv->selected_iter = 1;
}
static void
_gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
tree_view->priv->edited_column = NULL;
- gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ if (GTK_WIDGET_HAS_FOCUS (cell_editable))
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
gtk_container_remove (GTK_CONTAINER (tree_view),
GTK_WIDGET (cell_editable));
cursor_path,
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,