#include "gtkcellrenderer.h"
#include "gtksignal.h"
#include "gtkmain.h"
+#include "gtkmarshalers.h"
#include "gtkbutton.h"
#include "gtkalignment.h"
#include "gtklabel.h"
#include "gtkbindings.h"
#include "gtkcontainer.h"
#include "gtkentry.h"
+#include "gtktreemodelsort.h"
#include <string.h>
#include <gdk/gdkkeysyms.h>
-#if defined (GDK_WINDOWING_X11)
-#include "x11/gdkx.h"
-#elif defined (GDK_WINDOWING_WIN32)
-#include "win32/gdkwin32.h"
-#elif defined(GDK_WINDOWING_FB)
-#include "linux-fb/gdkfb.h"
-#elif defined (GDK_WINDOWING_NANOX)
-#include "nanox/gdkprivate-nanox.h"
-#endif
-
-
+#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_NUM_ROWS_PER_IDLE 50
#define SCROLL_EDGE_SIZE 15
#define EXPANDER_EXTRA_PADDING 4
* The "cell" areas are the cell_area passed in to gtk_cell_renderer_render(),
* i.e. just the cells, no spacing.
*/
-#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (_gtk_rbtree_node_find_offset ((tree), (node)) + TREE_VIEW_HEADER_HEIGHT ((tree_view)))
-#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
#define BACKGROUND_HEIGHT(node) (GTK_RBNODE_GET_HEIGHT (node))
#define CELL_HEIGHT(node, separator) (BACKGROUND_HEIGHT (node) - separator);
-#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view))
-#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view))
+#define TREE_WINDOW_Y_TO_RBTREE_Y(tree_view,y) ((y) - TREE_VIEW_HEADER_HEIGHT (tree_view) + tree_view->priv->dy)
+#define RBTREE_Y_TO_TREE_WINDOW_Y(tree_view,y) ((y) + TREE_VIEW_HEADER_HEIGHT (tree_view) - tree_view->priv->dy)
+
+/* This is in Window coordinates */
+#define BACKGROUND_FIRST_PIXEL(tree_view,tree,node) (RBTREE_Y_TO_TREE_WINDOW_Y (tree_view, _gtk_rbtree_node_find_offset ((tree), (node))))
+#define CELL_FIRST_PIXEL(tree_view,tree,node,separator) (BACKGROUND_FIRST_PIXEL (tree_view,tree,node) + separator/2)
typedef struct _GtkTreeViewChild GtkTreeViewChild;
GtkWidget *widget;
gint x;
gint y;
+ gint width;
+ gint height;
};
GdkModifierType start_button_mask;
GtkTargetList *source_target_list;
GdkDragAction source_actions;
- GClosure *row_draggable_closure;
GtkTargetList *dest_target_list;
- GClosure *location_droppable_closure;
guint source_set : 1;
guint dest_set : 1;
ROW_EXPANDED,
ROW_COLLAPSED,
COLUMNS_CHANGED,
- BEGIN_EXTENDED_SELECTION,
- END_EXTENDED_SELECTION,
- BEGIN_FREE_MOTION,
- END_FREE_MOTION,
+ CURSOR_CHANGED,
MOVE_CURSOR,
+ SELECT_ALL,
SELECT_CURSOR_ROW,
TOGGLE_CURSOR_ROW,
EXPAND_COLLAPSE_CURSOR_ROW,
SELECT_CURSOR_PARENT,
+ START_INTERACTIVE_SEARCH,
LAST_SIGNAL
};
GdkEventButton *event);
static void gtk_tree_view_set_focus_child (GtkContainer *container,
GtkWidget *child);
-static void gtk_tree_view_draw_focus (GtkWidget *widget);
static gint gtk_tree_view_focus_in (GtkWidget *widget,
GdkEventFocus *event);
static gint gtk_tree_view_focus_out (GtkWidget *widget,
static void gtk_tree_view_set_adjustments (GtkTreeView *tree_view,
GtkAdjustment *hadj,
GtkAdjustment *vadj);
-static void gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view);
-static void gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view);
-static void gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view);
-static void gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view);
static void gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
GtkMovementStep step,
gint count);
-static void gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view);
+static void gtk_tree_view_real_select_all (GtkTreeView *tree_view);
+static void 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 void gtk_tree_view_range_changed (GtkTreeModel *model,
+static void gtk_tree_view_row_changed (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
- GtkTreePath *end_path,
- GtkTreeIter *end_iter,
gpointer data);
-static void gtk_tree_view_inserted (GtkTreeModel *model,
+static void gtk_tree_view_row_inserted (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data);
-static void gtk_tree_view_has_child_toggled (GtkTreeModel *model,
+static void gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data);
-static void gtk_tree_view_deleted (GtkTreeModel *model,
+static void gtk_tree_view_row_deleted (GtkTreeModel *model,
GtkTreePath *path,
gpointer data);
-static void gtk_tree_view_reordered (GtkTreeModel *model,
+static void gtk_tree_view_rows_reordered (GtkTreeModel *model,
GtkTreePath *parent,
GtkTreeIter *iter,
gint *new_order,
gpointer data);
+/* Incremental reflow */
+static gboolean validate_row (GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node,
+ GtkTreeIter *iter,
+ GtkTreePath *path);
+static void validate_visible_area (GtkTreeView *tree_view);
+static gboolean validate_rows_handler (GtkTreeView *tree_view);
+static gboolean presize_handler_callback (gpointer data);
+static void install_presize_handler (GtkTreeView *tree_view);
/* Internal functions */
gint x,
gint y);
static void gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
+ GtkRBTree *tree,
gint *x1,
gint *x2);
static gint gtk_tree_view_new_column_width (GtkTreeView *tree_view,
gint i,
gint *x);
-static void gtk_tree_view_ensure_scroll_timeout (GtkTreeView *tree_view,
- GFunc func);
static void gtk_tree_view_adjustment_changed (GtkAdjustment *adjustment,
GtkTreeView *tree_view);
-static gint gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth);
static void gtk_tree_view_build_tree (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkTreeIter *iter,
gint depth,
- gboolean recurse,
- gboolean calc_bounds);
-static void gtk_tree_view_calc_size (GtkTreeView *priv,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth);
+ gboolean recurse);
static gboolean gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
GtkTreeIter *iter,
gint depth,
GtkRBTree *tree,
GtkTreeIter *iter,
gint depth);
-static void gtk_tree_view_check_dirty (GtkTreeView *tree_view);
static void gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node);
+static void gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column);
static gboolean gtk_tree_view_maybe_begin_dragging_row (GtkTreeView *tree_view,
GdkEventMotion *event);
-static void _gtk_tree_view_update_col_width (GtkTreeView *tree_view);
static void gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view);
static void gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view,
gint count);
static gboolean gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
GtkTreePath *path,
GtkRBTree *tree,
- GtkRBNode *node);
+ GtkRBNode *node,
+ gboolean animate);
static gboolean gtk_tree_view_real_expand_row (GtkTreeView *tree_view,
GtkTreePath *path,
GtkRBTree *tree,
GtkRBNode *node,
- gboolean open_all);
+ gboolean open_all,
+ gboolean animate);
static void gtk_tree_view_real_set_cursor (GtkTreeView *tree_view,
GtkTreePath *path,
gboolean clear_and_select);
-
/* interactive search */
static void gtk_tree_view_search_dialog_destroy (GtkWidget *search_dialog,
GtkTreeView *tree_view);
gboolean up);
static gboolean gtk_tree_view_search_equal_func (GtkTreeModel *model,
gint column,
- gchar *key,
- GtkTreeIter *iter);
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer search_data);
static gboolean gtk_tree_view_search_iter (GtkTreeModel *model,
GtkTreeSelection *selection,
GtkTreeIter *iter,
- gchar *text,
+ const gchar *text,
gint *count,
gint n);
static void gtk_tree_view_search_init (GtkWidget *entry,
GtkTreeView *tree_view);
-static void gtk_tree_view_interactive_search (GtkTreeView *tree_view,
- GdkEventKey *key);
+static void gtk_tree_view_put (GtkTreeView *tree_view,
+ GtkWidget *child_widget,
+ gint x,
+ gint y,
+ gint width,
+ gint height);
+static gboolean gtk_tree_view_start_editing (GtkTreeView *tree_view,
+ GtkTreePath *cursor_path);
+static void gtk_tree_view_real_start_editing (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column,
+ GtkTreePath *path,
+ GtkCellEditable *cell_editable,
+ GdkRectangle *cell_area,
+ GdkEvent *event,
+ guint flags);
+static void gtk_tree_view_stop_editing (GtkTreeView *tree_view);
+static void gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view);
static GtkContainerClass *parent_class = NULL;
-static guint tree_view_signals[LAST_SIGNAL] = { 0 };
+static guint tree_view_signals [LAST_SIGNAL] = { 0 };
\f
container_class->set_focus_child = gtk_tree_view_set_focus_child;
class->set_scroll_adjustments = gtk_tree_view_set_adjustments;
- class->begin_extended_selection = gtk_tree_view_real_begin_extended_selection;
- class->end_extended_selection = gtk_tree_view_real_end_extended_selection;
- class->begin_free_motion = gtk_tree_view_real_begin_free_motion;
- class->end_free_motion = gtk_tree_view_real_end_free_motion;
class->move_cursor = gtk_tree_view_real_move_cursor;
+ class->select_all = gtk_tree_view_real_select_all;
class->select_cursor_row = gtk_tree_view_real_select_cursor_row;
class->toggle_cursor_row = gtk_tree_view_real_toggle_cursor_row;
class->expand_collapse_cursor_row = gtk_tree_view_real_expand_collapse_cursor_row;
class->select_cursor_parent = gtk_tree_view_real_select_cursor_parent;
+ class->start_interactive_search = gtk_tree_view_real_start_interactive_search;
/* Properties */
_("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",
G_MAXINT,
0,
G_PARAM_READWRITE));
-
+
/* Style properties */
- /* the width of the column resize windows */
#define _TREE_VIEW_EXPANDER_SIZE 10
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
-#define _TREE_VIEW_HORIZONTAL_SEPARATOR 0
-
+#define _TREE_VIEW_HORIZONTAL_SEPARATOR 2
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("expander_size",
_("Expander Size"),
- _("Size of the expander arrow"),
+ _("Size of the expander arrow."),
0,
G_MAXINT,
_TREE_VIEW_EXPANDER_SIZE,
G_PARAM_READABLE));
-
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("vertical_separator",
_("Vertical Separator Width"),
- _("Vertical space between cells"),
+ _("Vertical space between cells. Must be an even number."),
0,
G_MAXINT,
_TREE_VIEW_VERTICAL_SEPARATOR,
G_PARAM_READABLE));
-
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("horizontal_separator",
_("Horizontal Separator Width"),
- _("Horizontal space between cells"),
+ _("Horizontal space between cells. Must be an even number."),
0,
G_MAXINT,
_TREE_VIEW_HORIZONTAL_SEPARATOR,
G_PARAM_READABLE));
+ gtk_widget_class_install_style_property (widget_class,
+ g_param_spec_boolean ("allow_rules",
+ _("Allow Rules"),
+ _("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."),
+ TRUE,
+ G_PARAM_READABLE));
/* Signals */
widget_class->set_scroll_adjustments_signal =
gtk_signal_new ("set_scroll_adjustments",
GTK_RUN_LAST,
GTK_CLASS_TYPE (object_class),
GTK_SIGNAL_OFFSET (GtkTreeViewClass, set_scroll_adjustments),
- gtk_marshal_VOID__OBJECT_OBJECT,
+ _gtk_marshal_VOID__OBJECT_OBJECT,
GTK_TYPE_NONE, 2,
GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
GTK_RUN_LAST | GTK_RUN_ACTION,
GTK_CLASS_TYPE (object_class),
GTK_SIGNAL_OFFSET (GtkTreeViewClass, row_activated),
- gtk_marshal_VOID__BOXED_OBJECT,
+ _gtk_marshal_VOID__BOXED_OBJECT,
GTK_TYPE_NONE, 2,
GTK_TYPE_TREE_PATH,
GTK_TYPE_TREE_VIEW_COLUMN);
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, test_expand_row),
_gtk_boolean_handled_accumulator, NULL,
- gtk_marshal_BOOLEAN__BOXED_BOXED,
+ _gtk_marshal_BOOLEAN__BOXED_BOXED,
G_TYPE_BOOLEAN, 2,
GTK_TYPE_TREE_ITER,
GTK_TYPE_TREE_PATH);
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, test_collapse_row),
_gtk_boolean_handled_accumulator, NULL,
- gtk_marshal_BOOLEAN__BOXED_BOXED,
+ _gtk_marshal_BOOLEAN__BOXED_BOXED,
G_TYPE_BOOLEAN, 2,
GTK_TYPE_TREE_ITER,
GTK_TYPE_TREE_PATH);
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, row_expanded),
NULL, NULL,
- gtk_marshal_VOID__BOXED_BOXED,
+ _gtk_marshal_VOID__BOXED_BOXED,
GTK_TYPE_NONE, 2,
GTK_TYPE_TREE_ITER,
GTK_TYPE_TREE_PATH);
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, row_collapsed),
NULL, NULL,
- gtk_marshal_VOID__BOXED_BOXED,
+ _gtk_marshal_VOID__BOXED_BOXED,
GTK_TYPE_NONE, 2,
GTK_TYPE_TREE_ITER,
GTK_TYPE_TREE_PATH);
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewClass, columns_changed),
NULL, NULL,
- gtk_marshal_NONE__NONE,
+ _gtk_marshal_NONE__NONE,
G_TYPE_NONE, 0);
- tree_view_signals[BEGIN_EXTENDED_SELECTION] =
- g_signal_new ("begin_extended_selection",
+ tree_view_signals[CURSOR_CHANGED] =
+ g_signal_new ("cursor_changed",
G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
- G_STRUCT_OFFSET (GtkTreeViewClass, begin_extended_selection),
- NULL, NULL,
- gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- tree_view_signals[END_EXTENDED_SELECTION] =
- g_signal_new ("end_extended_selection",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
- G_STRUCT_OFFSET (GtkTreeViewClass, end_extended_selection),
- NULL, NULL,
- gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- tree_view_signals[BEGIN_FREE_MOTION] =
- g_signal_new ("begin_free_motion",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
- G_STRUCT_OFFSET (GtkTreeViewClass, begin_free_motion),
- NULL, NULL,
- gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
-
- tree_view_signals[END_FREE_MOTION] =
- g_signal_new ("end_free_motion",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
- G_STRUCT_OFFSET (GtkTreeViewClass, end_free_motion),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkTreeViewClass, cursor_changed),
NULL, NULL,
- gtk_marshal_NONE__NONE,
+ _gtk_marshal_NONE__NONE,
G_TYPE_NONE, 0);
tree_view_signals[MOVE_CURSOR] =
G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, move_cursor),
NULL, NULL,
- gtk_marshal_VOID__ENUM_INT,
+ _gtk_marshal_VOID__ENUM_INT,
GTK_TYPE_NONE, 2, GTK_TYPE_MOVEMENT_STEP, GTK_TYPE_INT);
+ tree_view_signals[SELECT_ALL] =
+ g_signal_new ("select_all",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
+ G_STRUCT_OFFSET (GtkTreeViewClass, select_all),
+ NULL, NULL,
+ _gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+
tree_view_signals[SELECT_CURSOR_ROW] =
g_signal_new ("select_cursor_row",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_row),
NULL, NULL,
- gtk_marshal_NONE__NONE,
- GTK_TYPE_NONE, 0);
+ _gtk_marshal_VOID__BOOLEAN,
+ GTK_TYPE_NONE, 1,
+ G_TYPE_BOOLEAN);
tree_view_signals[TOGGLE_CURSOR_ROW] =
g_signal_new ("toggle_cursor_row",
G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, toggle_cursor_row),
NULL, NULL,
- gtk_marshal_NONE__NONE,
+ _gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
tree_view_signals[EXPAND_COLLAPSE_CURSOR_ROW] =
G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, expand_collapse_cursor_row),
NULL, NULL,
- gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
+ _gtk_marshal_VOID__BOOLEAN_BOOLEAN_BOOLEAN,
GTK_TYPE_NONE, 3, GTK_TYPE_BOOL, GTK_TYPE_BOOL, GTK_TYPE_BOOL);
tree_view_signals[SELECT_CURSOR_PARENT] =
G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
G_STRUCT_OFFSET (GtkTreeViewClass, select_cursor_parent),
NULL, NULL,
- gtk_marshal_NONE__NONE,
+ _gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
- /* Key bindings */
- gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, 0, "begin_extended_selection", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Shift_L, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Control_L, 0, "begin_free_motion", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Control_L, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, 0, "begin_extended_selection", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Shift_R, GDK_SHIFT_MASK | GDK_RELEASE_MASK, "end_extended_selection", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Control_R, 0, "begin_free_motion", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_Control_R, GDK_CONTROL_MASK | GDK_RELEASE_MASK, "end_free_motion", 0);
+ tree_view_signals[START_INTERACTIVE_SEARCH] =
+ g_signal_new ("start_interactive_search",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | GTK_RUN_ACTION,
+ G_STRUCT_OFFSET (GtkTreeViewClass, start_interactive_search),
+ NULL, NULL,
+ _gtk_marshal_NONE__NONE,
+ GTK_TYPE_NONE, 0);
+ /* Key bindings */
gtk_tree_view_add_move_binding (binding_set, GDK_Up, 0,
GTK_MOVEMENT_DISPLAY_LINES, -1);
GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
GTK_TYPE_INT, -1);
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK, "move_cursor", 2,
+ GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ GTK_TYPE_INT, 1);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK, "move_cursor", 2,
+ GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ GTK_TYPE_INT, -1);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
+ GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ GTK_TYPE_INT, 1);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, GDK_CONTROL_MASK|GDK_SHIFT_MASK, "move_cursor", 2,
+ GTK_TYPE_ENUM, GTK_MOVEMENT_VISUAL_POSITIONS,
+ GTK_TYPE_INT, -1);
+
gtk_binding_entry_add_signal (binding_set, GDK_f, GDK_CONTROL_MASK, "move_cursor", 2,
GTK_TYPE_ENUM, GTK_MOVEMENT_LOGICAL_POSITIONS,
GTK_TYPE_INT, 1);
gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_CONTROL_MASK, "toggle_cursor_row", 0);
- gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_a, GDK_CONTROL_MASK, "select_all", 0);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_space, GDK_SHIFT_MASK, "select_cursor_row", 1,
+ GTK_TYPE_BOOL, TRUE);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_space, 0, "select_cursor_row", 1,
+ GTK_TYPE_BOOL, TRUE);
/* expand and collapse rows */
gtk_binding_entry_add_signal (binding_set, GDK_plus, 0, "expand_collapse_cursor_row", 3,
gtk_binding_entry_add_signal (binding_set, GDK_BackSpace, 0, "select_cursor_parent", 0);
+ gtk_binding_entry_add_signal (binding_set, GDK_s, GDK_CONTROL_MASK, "start_interactive_search", 0);
+
+ gtk_binding_entry_add_signal (binding_set, GDK_S, GDK_CONTROL_MASK, "start_interactive_search", 0);
}
static void
gtk_tree_view_init (GtkTreeView *tree_view)
{
tree_view->priv = g_new0 (GtkTreeViewPrivate, 1);
-
GTK_WIDGET_SET_FLAGS (tree_view, GTK_CAN_FOCUS);
tree_view->priv->flags = GTK_TREE_VIEW_IS_LIST | GTK_TREE_VIEW_SHOW_EXPANDERS | GTK_TREE_VIEW_DRAW_KEYFOCUS | GTK_TREE_VIEW_HEADERS_VISIBLE;
/* We need some padding */
tree_view->priv->tab_offset += EXPANDER_EXTRA_PADDING;
-
+ tree_view->priv->dy = 0;
tree_view->priv->n_columns = 0;
tree_view->priv->header_height = 1;
tree_view->priv->x_drag = 0;
tree_view->priv->press_start_x = -1;
tree_view->priv->press_start_y = -1;
tree_view->priv->reorderable = FALSE;
+ tree_view->priv->presize_handler_timer = 0;
gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
tree_view->priv->selection = _gtk_tree_selection_new_with_tree_view (tree_view);
- _gtk_tree_view_update_size (tree_view);
tree_view->priv->enable_search = TRUE;
tree_view->priv->search_column = -1;
tree_view->priv->search_dialog_position_func = gtk_tree_view_search_position_func;
}
static void
-gtk_tree_view_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
+gtk_tree_view_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
{
GtkTreeView *tree_view;
switch (prop_id)
{
case PROP_MODEL:
- g_value_set_object (value, G_OBJECT (tree_view->priv->model));
+ g_value_set_object (value, tree_view->priv->model);
break;
case PROP_HADJUSTMENT:
g_value_set_object (value, G_OBJECT (tree_view->priv->hadjustment));
g_value_set_boolean (value, gtk_tree_view_get_headers_visible (tree_view));
break;
case PROP_EXPANDER_COLUMN:
- g_value_set_object (value, G_OBJECT (tree_view->priv->expander_column));
+ g_value_set_object (value, tree_view->priv->expander_column);
break;
case PROP_REORDERABLE:
g_value_set_boolean (value, tree_view->priv->reorderable);
GtkWidget *search_dialog;
GList *list;
- if (tree_view->priv->columns != NULL)
+ gtk_tree_view_stop_editing (tree_view);
+
+ if (tree_view->priv->columns != NULL)
{
- for (list = tree_view->priv->columns; list; list = list->next)
- g_object_unref (G_OBJECT (list->data));
- g_list_free (tree_view->priv->columns);
+ list = tree_view->priv->columns;
+ while (list)
+ {
+ GtkTreeViewColumn *column;
+ column = GTK_TREE_VIEW_COLUMN (list->data);
+ list = list->next;
+ gtk_tree_view_remove_column (tree_view, column);
+ }
tree_view->priv->columns = NULL;
}
tree_view->priv->drag_dest_row = NULL;
}
-
+
if (tree_view->priv->column_drop_func_data &&
tree_view->priv->column_drop_func_data_destroy)
{
tree_view->priv->anchor = NULL;
/* destroy interactive search dialog */
- search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view), "search-dialog");
+ search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
if (search_dialog)
gtk_tree_view_search_dialog_destroy (search_dialog,
- tree_view);
+ tree_view);
+ if (tree_view->priv->search_user_data)
+ {
+ (* tree_view->priv->search_destroy) (tree_view->priv->search_user_data);
+ tree_view->priv->search_user_data = NULL;
+ }
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}
column = list->data;
if (column->visible == FALSE)
continue;
- if (column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE)
+ if (column->resizable)
{
gdk_window_raise (column->window);
gdk_window_show (column->window);
tree_view = GTK_TREE_VIEW (widget);
- gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
/* Make the main, clipping window */
attributes.x = 0;
attributes.y = 0;
attributes.width = tree_view->priv->width;
- attributes.height = tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view);
+ attributes.height = widget->allocation.height;
attributes.event_mask = GDK_EXPOSURE_MASK |
GDK_SCROLL_MASK |
GDK_POINTER_MOTION_MASK |
widget->style->black:widget->style->white);
values.function = GDK_XOR;
values.subwindow_mode = GDK_INCLUDE_INFERIORS;
- tree_view->priv->xor_gc = gdk_gc_new_with_values (widget->window,
- &values,
- GDK_GC_FOREGROUND |
- GDK_GC_FUNCTION |
- GDK_GC_SUBWINDOW);
+
/* Add them all up. */
widget->style = gtk_style_attach (widget->style, widget->window);
gdk_window_set_background (widget->window, &widget->style->base[widget->state]);
for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
_gtk_tree_view_column_realize_button (GTK_TREE_VIEW_COLUMN (tmp_list->data));
- _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
+ install_presize_handler (tree_view);
- if (tree_view->priv->scroll_to_path != NULL ||
- tree_view->priv->scroll_to_column != NULL)
- {
- gtk_tree_view_scroll_to_cell (tree_view,
- tree_view->priv->scroll_to_path,
- tree_view->priv->scroll_to_column,
- tree_view->priv->scroll_to_row_align,
- tree_view->priv->scroll_to_col_align);
- if (tree_view->priv->scroll_to_path)
- {
- gtk_tree_path_free (tree_view->priv->scroll_to_path);
- tree_view->priv->scroll_to_path = NULL;
- }
- tree_view->priv->scroll_to_column = NULL;
- }
+ if (GTK_WIDGET_CLASS (parent_class)->map)
+ (* GTK_WIDGET_CLASS (parent_class)->map) (widget);
}
static void
tree_view->priv->expand_collapse_timeout = 0;
}
+ if (tree_view->priv->presize_handler_timer != 0)
+ {
+ gtk_timeout_remove (tree_view->priv->presize_handler_timer);
+ tree_view->priv->presize_handler_timer = 0;
+ }
+
for (list = tree_view->priv->columns; list; list = list->next)
_gtk_tree_view_column_unrealize_button (GTK_TREE_VIEW_COLUMN (list->data));
tree_view->priv->drag_highlight_window = NULL;
}
- if (tree_view->priv->cursor_drag)
- {
- gdk_cursor_destroy (tree_view->priv->cursor_drag);
- tree_view->priv->cursor_drag = NULL;
- }
-
- if (tree_view->priv->xor_gc)
- {
- gdk_gc_destroy (tree_view->priv->xor_gc);
- tree_view->priv->xor_gc = NULL;
- }
-
/* GtkWidget::unrealize destroys children and widget->window */
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
/* GtkWidget::size_request helper */
static void
-gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
+gtk_tree_view_size_request_columns (GtkTreeView *tree_view)
{
GList *list;
- tree_view->priv->header_height = 1;
+ tree_view->priv->header_height = 0;
if (tree_view->priv->model)
{
continue;
column = list->data;
-
+
gtk_widget_size_request (column->button, &requisition);
-
- _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
+ column->button_request = requisition.width;
tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
}
}
}
+
+static void
+gtk_tree_view_update_size (GtkTreeView *tree_view)
+{
+ GList *list;
+ GtkTreeViewColumn *column;
+ gint i;
+
+ if (tree_view->priv->model == NULL)
+ {
+ tree_view->priv->width = 0;
+ tree_view->priv->height = 0;
+ return;
+ }
+
+ 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++)
+ {
+ gint real_requested_width = 0;
+ column = list->data;
+ if (!column->visible)
+ 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 (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);
+
+ tree_view->priv->width += real_requested_width;
+ }
+
+ if (tree_view->priv->tree == NULL)
+ tree_view->priv->height = 0;
+ else
+ tree_view->priv->height = tree_view->priv->tree->root->offset;
+}
+
static void
gtk_tree_view_size_request (GtkWidget *widget,
GtkRequisition *requisition)
tree_view = GTK_TREE_VIEW (widget);
+ gtk_tree_view_size_request_columns (tree_view);
+ gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
+
requisition->width = tree_view->priv->width;
requisition->height = tree_view->priv->height + tree_view->priv->header_height;
if (GTK_WIDGET_VISIBLE (child->widget))
gtk_widget_size_request (child->widget, &child_requisition);
}
-
- gtk_tree_view_size_request_buttons (tree_view);
}
/* GtkWidget::size_allocate helper */
static void
-gtk_tree_view_size_allocate_buttons (GtkWidget *widget)
+gtk_tree_view_size_allocate_columns (GtkWidget *widget)
{
GtkTreeView *tree_view;
- GList *list;
+ GList *list, *last_column;
GtkTreeViewColumn *column;
GtkAllocation allocation;
gint width = 0;
tree_view = GTK_TREE_VIEW (widget);
+ 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)
+ ;
+ if (last_column == NULL)
+ return;
+
allocation.y = 0;
allocation.height = tree_view->priv->header_height;
- for (list = tree_view->priv->columns; list != NULL; list = list->next)
+ for (list = tree_view->priv->columns; list != last_column->next; list = list->next)
{
+ gint real_requested_width = 0;
column = list->data;
-
if (!column->visible)
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 (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);
+
allocation.x = width;
- allocation.width = column->displayed_width;
+ column->width = real_requested_width;
+ if (list == last_column &&
+ width + real_requested_width < widget->allocation.width)
+ {
+ column->width += (widget->allocation.width - column->width - width);
+ }
+ g_object_notify (G_OBJECT (column), "width");
+ allocation.width = column->width;
width += column->width;
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,
tree_view = GTK_TREE_VIEW (widget);
- gtk_tree_view_check_dirty (tree_view);
-
tmp_list = tree_view->priv->children;
while (tmp_list)
{
GtkAllocation allocation;
- GtkRequisition requisition;
GtkTreeViewChild *child = tmp_list->data;
tmp_list = tmp_list->next;
+ /* totally ignore our childs requisition */
allocation.x = child->x;
allocation.y = child->y;
- gtk_widget_get_child_requisition (child->widget, &requisition);
- allocation.width = requisition.width;
- allocation.height = requisition.height;
-
+ allocation.width = child->width;
+ allocation.height = child->height;
gtk_widget_size_allocate (child->widget, &allocation);
}
gdk_window_resize (tree_view->priv->header_window,
MAX (tree_view->priv->width, allocation->width),
tree_view->priv->header_height);
- if (tree_view->priv->width < allocation->width)
- gdk_window_resize (tree_view->priv->bin_window,
- allocation->width,
- tree_view->priv->height + TREE_VIEW_HEADER_HEIGHT (tree_view));
-
- _gtk_tree_view_update_col_width (tree_view);
+ gdk_window_resize (tree_view->priv->bin_window,
+ MAX (tree_view->priv->width, allocation->width),
+ allocation->height);
}
- gtk_tree_view_size_allocate_buttons (widget);
+ gtk_tree_view_size_allocate_columns (widget);
tree_view->priv->hadjustment->page_size = allocation->width;
tree_view->priv->hadjustment->page_increment = allocation->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);
- gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
+ 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->step_increment = (tree_view->priv->vadjustment->page_size) / 10;
if (tree_view->priv->vadjustment->value + allocation->height > tree_view->priv->height)
gtk_adjustment_set_value (tree_view->priv->vadjustment,
MAX (tree_view->priv->height - allocation->height, 0));
+ gtk_adjustment_changed (tree_view->priv->vadjustment);
- gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
-
+ if (tree_view->priv->scroll_to_path != NULL ||
+ tree_view->priv->scroll_to_column != NULL)
+ {
+ gtk_tree_view_scroll_to_cell (tree_view,
+ tree_view->priv->scroll_to_path,
+ tree_view->priv->scroll_to_column,
+ tree_view->priv->scroll_to_use_align,
+ tree_view->priv->scroll_to_row_align,
+ tree_view->priv->scroll_to_col_align);
+ if (tree_view->priv->scroll_to_path)
+ {
+ gtk_tree_path_free (tree_view->priv->scroll_to_path);
+ tree_view->priv->scroll_to_path = NULL;
+ }
+ tree_view->priv->scroll_to_column = NULL;
+ }
}
static gboolean
GdkRectangle background_area;
GdkRectangle cell_area;
gint vertical_separator;
+ gint horizontal_separator;
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);
- gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
+ gtk_tree_view_stop_editing (tree_view);
+ gtk_widget_style_get (widget,
+ "vertical_separator", &vertical_separator,
+ "horizontal_separator", &horizontal_separator,
+ NULL);
if (event->window == tree_view->priv->bin_window)
{
gint new_y;
gint y_offset;
GtkTreeViewColumn *column = NULL;
+ gint column_handled_click = FALSE;
if (!GTK_WIDGET_HAS_FOCUS (widget))
gtk_widget_grab_focus (widget);
}
/* find the node that was clicked */
- new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
- y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
- &tree,
- &node) + new_y - (gint)event->y;
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
+ if (new_y < 0)
+ new_y = 0;
+ y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
if (node == NULL)
/* We clicked in dead space */
/* Get the path and the node */
path = _gtk_tree_view_find_path (tree_view, tree, node);
depth = gtk_tree_path_get_depth (path);
- background_area.y = y_offset + event->y + vertical_separator;
- background_area.height = GTK_RBNODE_GET_HEIGHT (node) - vertical_separator;
+ background_area.y = y_offset + event->y;
+ background_area.height = GTK_RBNODE_GET_HEIGHT (node);
background_area.x = 0;
/* Let the column have a chance at selecting it. */
for (list = tree_view->priv->columns; list; list = list->next)
{
- GtkTreeIter iter;
-
column = list->data;
if (!column->visible)
continue;
- background_area.width = column->displayed_width;
+ background_area.width = column->width;
+ if ((background_area.x > (gint) event->x) ||
+ (background_area.x + background_area.width <= (gint) event->x))
+ {
+ background_area.x += background_area.width;
+ continue;
+ }
+
+ /* we found the focus column */
+ cell_area = background_area;
+ cell_area.width -= horizontal_separator;
+ cell_area.height -= vertical_separator;
+ cell_area.x += horizontal_separator/2;
+ cell_area.y += vertical_separator/2;
if (gtk_tree_view_is_expander_column (tree_view, column) &&
TREE_VIEW_DRAW_EXPANDERS(tree_view))
{
- cell_area = background_area;
cell_area.x += depth*tree_view->priv->tab_offset;
cell_area.width -= depth*tree_view->priv->tab_offset;
}
- else
- {
- cell_area = background_area;
- }
+ break;
+ }
- if ((background_area.x > (gint) event->x) ||
- (background_area.y > (gint) event->y) ||
- (background_area.x + background_area.width <= (gint) event->x) ||
- (background_area.y + background_area.height <= (gint) event->y))
- {
- background_area.x += background_area.width;
- continue;
- }
+ if (column == NULL)
+ return FALSE;
+
+ tree_view->priv->focus_column = column;
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
+ 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);
+ gtk_tree_view_real_select_cursor_row (tree_view, FALSE);
+ }
+ else
+ {
+ gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
+ }
+
+ if (event->type == GDK_BUTTON_PRESS &&
+ !event->state)
+ {
+ GtkCellEditable *cell_editable = NULL;
+ /* FIXME: get the right flags */
+ guint flags = 0;
+ GtkTreeIter iter;
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
gtk_tree_view_column_cell_set_cell_data (column,
path_string = gtk_tree_path_to_string (path);
- if (gtk_tree_view_column_cell_event (column,
- (GdkEvent *)event,
- path_string,
- &background_area,
- &cell_area, 0))
- {
- g_free (path_string);
- gtk_tree_path_free (path);
- return TRUE;
- }
- else
+ if (_gtk_tree_view_column_cell_event (column,
+ &cell_editable,
+ (GdkEvent *)event,
+ path_string,
+ &background_area,
+ &cell_area, flags))
{
- g_free (path_string);
- break;
+ if (cell_editable != NULL)
+ {
+ gtk_tree_view_real_start_editing (tree_view,
+ column,
+ path,
+ cell_editable,
+ &cell_area,
+ (GdkEvent *)event,
+ flags);
+
+ }
+ column_handled_click = TRUE;
}
+ g_free (path_string);
}
- if (column == NULL)
- return FALSE;
-
- /* The columns didn't want the event. We handle it */
-
/* Save press to possibly begin a drag
*/
- if (tree_view->priv->pressed_button < 0)
+ if (!column_handled_click &&
+ tree_view->priv->pressed_button < 0)
{
tree_view->priv->pressed_button = event->button;
tree_view->priv->press_start_x = event->x;
tree_view->priv->press_start_y = event->y;
}
- gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
-
if (event->button == 1 && event->type == GDK_2BUTTON_PRESS)
{
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
{
if (node->children == NULL)
gtk_tree_view_real_expand_row (tree_view, path,
- tree, node, FALSE);
+ tree, node, FALSE, TRUE);
else
gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
- tree, node);
+ tree, node, TRUE);
}
- gtk_tree_view_row_activated (tree_view, path, column);
+ gtk_tree_view_row_activated (tree_view, path, column);
}
+ GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
gtk_tree_path_free (path);
return TRUE;
}
{
column = list->data;
if (event->window == column->window &&
- column->column_type == GTK_TREE_VIEW_COLUMN_RESIZABLE &&
+ column->resizable &&
column->window)
{
gpointer drag_data;
gtk_grab_add (widget);
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_IN_COLUMN_RESIZE);
+ column->resized_width = column->width;
+ column->use_resized_width = TRUE;
/* block attached dnd signal handler */
drag_data = gtk_object_get_data (GTK_OBJECT (widget), "gtk-site-data");
tree_view->priv->drag_pos = i;
tree_view->priv->x_drag = (column->button->allocation.x + column->button->allocation.width);
+ break;
}
}
return TRUE;
{
GtkTreeView *tree_view;
gpointer drag_data;
- gint width;
gint x;
gint i;
gtk_grab_remove (widget);
gdk_pointer_ungrab (event->time);
- width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
- _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
-
return TRUE;
}
gtk_tree_view_real_expand_row (tree_view, path,
tree_view->priv->button_pressed_tree,
tree_view->priv->button_pressed_node,
- FALSE);
+ FALSE, TRUE);
else
gtk_tree_view_real_collapse_row (GTK_TREE_VIEW (widget), path,
tree_view->priv->button_pressed_tree,
- tree_view->priv->button_pressed_node);
+ tree_view->priv->button_pressed_node, TRUE);
gtk_tree_path_free (path);
}
coords_are_over_arrow (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
- /* these are in tree window coords */
+ /* these are in window coords */
gint x,
gint y)
{
arrow.height = BACKGROUND_HEIGHT (node);
- gtk_tree_view_get_arrow_xrange (tree_view, &arrow.x, &x2);
+ gtk_tree_view_get_arrow_xrange (tree_view, tree, &arrow.x, &x2);
arrow.width = x2 - arrow.x;
return (x >= arrow.x &&
x < (arrow.x + arrow.width) &&
- y >= arrow.y &&
- y < (arrow.y + arrow.height));
+ y >= arrow.y &&
+ y < (arrow.y + arrow.height));
}
static void
do_prelight (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkRBNode *node,
- /* these are in tree window coords */
+ /* these are in tree_window coords */
gint x,
gint y)
{
if (coords_are_over_arrow (tree_view, tree, node, x, y))
- GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
+ {
+ GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_ARROW_PRELIT);
+ }
tree_view->priv->prelight_node = node;
tree_view->priv->prelight_tree = tree;
+
/* Our motion arrow is either a box (in the case of the original spot)
* or an arrow. It is expander_size wide.
*/
NULL);
width = expander_size;
-
+
/* Get x, y, width, height of arrow */
if (reorder->left_column)
{
NULL);
width = expander_size;
-
+
/* Get x, y, width, height of arrow */
width = width/2; /* remember, the arrow only takes half the available width */
gdk_window_get_origin (widget->window, &x, &y);
{
gint x;
gint new_width;
+ GtkTreeViewColumn *column;
+
+ column = gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos);
if (event->is_hint || event->window != widget->window)
gtk_widget_get_pointer (widget, &x, NULL);
new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
- if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
- _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
+ if (x != GTK_TREE_VIEW (widget)->priv->x_drag &&
+ (new_width != column->fixed_width));
+ {
+ column->resized_width = new_width;
+ gtk_widget_queue_resize (widget);
+ }
- /* FIXME: Do we need to scroll */
- _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
return FALSE;
}
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);
- do_unprelight (tree_view, event->x, event->y);
- new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
-
- _gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
- &tree,
- &node);
+ 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;
return TRUE;
- do_prelight (tree_view, tree, node, event->x, new_y);
+ 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,
+ {
+ 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,
+ {
+ 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);
+ {
+ gtk_tree_view_queue_draw_node (tree_view,
+ tree_view->priv->prelight_tree,
+ tree_view->priv->prelight_node,
+ NULL);
+ }
}
return TRUE;
}
return FALSE;
}
-/* Draws the focus rectangle around the cursor row */
-static void
-gtk_tree_view_draw_focus (GtkWidget *widget)
-{
- GtkTreeView *tree_view;
- GtkTreePath *cursor_path;
- GtkRBTree *tree = NULL;
- GtkRBNode *node = NULL;
- gint x, y;
- gint width, height;
- gint vertical_separator;
-
- g_return_if_fail (GTK_IS_TREE_VIEW (widget));
-
- tree_view = GTK_TREE_VIEW (widget);
-
- gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
-
- if (! GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS))
- return;
-
- if (! gtk_tree_row_reference_valid (tree_view->priv->cursor))
- return;
-
- cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
-
- _gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node);
-
- if (tree == NULL)
- {
- gtk_tree_path_free (cursor_path);
- return;
- }
-
- gdk_drawable_get_size (tree_view->priv->bin_window,
- &width, NULL);
-
-
- x = 0;
- y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
- gdk_drawable_get_size (tree_view->priv->bin_window,
- &width, NULL);
- width = width - 1;
- height = BACKGROUND_HEIGHT (node) - 1;
- if (tree_view->priv->focus_column != NULL)
- {
- GtkTreeIter iter;
-
- gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
- gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
- tree_view->priv->model,
- &iter,
- GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
- node->children?TRUE:FALSE);
-
- if (gtk_tree_view_column_cell_can_focus (tree_view->priv->focus_column))
- {
- GdkRectangle cell_area;
- gint x_offset;
- gint y_offset;
-
- cell_area.x = tree_view->priv->focus_column->button->allocation.x;
- cell_area.y = y;
- cell_area.width = tree_view->priv->focus_column->displayed_width;
- cell_area.height = CELL_HEIGHT (node, vertical_separator);
-
- gtk_tree_view_column_cell_get_size (tree_view->priv->focus_column,
- &cell_area, &x_offset, &y_offset, &width, &height);
-
- width += 2;
- height += 2;
-
- x = cell_area.x + x_offset - 1;
- y = cell_area.y + y_offset - 1 + vertical_separator/2;
- }
- }
-
- gtk_paint_focus (widget->style,
- tree_view->priv->bin_window,
- NULL,
- widget,
- "treeview",
- x, y, width, height);
-
- gtk_tree_path_free (cursor_path);
-}
-
/* Warning: Very scary function.
* Modify at your own risk
+ *
+ * KEEP IN SYNC WITH gtk_tree_view_create_row_drag_icon()!
+ * FIXME: It's not...
*/
static gboolean
gtk_tree_view_bin_expose (GtkWidget *widget,
GtkTreePath *drag_dest_path;
GList *last_column;
gint vertical_separator;
+ gint horizontal_separator;
+ gboolean allow_rules;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
tree_view = GTK_TREE_VIEW (widget);
- gtk_widget_style_get (widget, "vertical_separator", &vertical_separator, NULL);
+
+ gtk_widget_style_get (widget,
+ "horizontal_separator", &horizontal_separator,
+ "vertical_separator", &vertical_separator,
+ "allow_rules", &allow_rules,
+ NULL);
if (tree_view->priv->tree == NULL)
return TRUE;
- gtk_tree_view_check_dirty (GTK_TREE_VIEW (widget));
- /* we want to account for a potential HEADER offset.
- * That is, if the header exists, we want to offset our event by its
- * height to find the right node.
- */
- new_y = (event->area.y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):event->area.y;
+ /* clip event->area to the visible area */
+ if (event->area.y < TREE_VIEW_HEADER_HEIGHT (tree_view))
+ {
+ event->area.height -= (TREE_VIEW_HEADER_HEIGHT (tree_view) - event->area.y);
+ event->area.y = TREE_VIEW_HEADER_HEIGHT (tree_view);
+
+ if (event->area.height < 0)
+ return TRUE;
+ }
- /* y_offset is the */
+ validate_visible_area (tree_view);
+
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, event->area.y);
+ if (new_y < 0)
+ new_y = 0;
+ y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree, new_y, &tree, &node);
- y_offset = -_gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
- &tree,
- &node) + new_y - event->area.y;
if (node == NULL)
return TRUE;
background_area.y = y_offset + event->area.y;
background_area.height = max_height;
+
flags = 0;
if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PRELIT))
flags |= GTK_CELL_RENDERER_SELECTED;
parity = _gtk_rbtree_node_find_parity (tree, node);
-
+
for (list = tree_view->priv->columns; list; list = list->next)
{
GtkTreeViewColumn *column = list->data;
const gchar *detail = NULL;
+ GtkStateType state;
if (!column->visible)
continue;
if (cell_offset > event->area.x + event->area.width ||
- cell_offset + column->displayed_width < event->area.x)
+ cell_offset + column->width < event->area.x)
{
- cell_offset += column->displayed_width;
+ cell_offset += column->width;
continue;
}
background_area.x = cell_offset;
- background_area.width = column->displayed_width;
+ background_area.width = column->width;
cell_area = background_area;
cell_area.y += vertical_separator / 2;
+ cell_area.x += horizontal_separator / 2;
cell_area.height -= vertical_separator;
+ cell_area.width -= horizontal_separator;
/* Select the detail for drawing the cell. relevant
* factors are parity, sortedness, and whether to
* display rules.
*/
-
- /* FIXME when we have style properties, clean this up.
- */
-
- if (tree_view->priv->has_rules)
+ if (allow_rules && tree_view->priv->has_rules)
{
if (flags & GTK_CELL_RENDERER_SORTED)
{
g_assert (detail);
- /* Draw background */
+ if (flags & GTK_CELL_RENDERER_SELECTED)
+ state = GTK_STATE_SELECTED;
+ else
+ state = GTK_STATE_NORMAL;
+
+ /* Draw background */
gtk_paint_flat_box (widget->style,
event->window,
- (flags & GTK_CELL_RENDERER_SELECTED) ?
- GTK_STATE_SELECTED : GTK_STATE_NORMAL,
+ state,
GTK_SHADOW_NONE,
&event->area,
widget,
* level of the tree we're dropping at.
*/
highlight_x = cell_area.x;
-
gtk_tree_view_column_cell_render (column,
event->window,
&background_area,
&event->area,
flags);
}
- cell_offset += column->displayed_width;
+ if (node == cursor &&
+ ((column == tree_view->priv->focus_column &&
+ GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS) &&
+ GTK_WIDGET_HAS_FOCUS (widget)) ||
+ (column == tree_view->priv->edited_column)))
+ {
+ gtk_tree_view_column_cell_draw_focus (column,
+ event->window,
+ &background_area,
+ &cell_area,
+ &event->area,
+ flags);
+ }
+ cell_offset += column->width;
}
- if (node == cursor && GTK_WIDGET_HAS_FOCUS (widget))
- gtk_tree_view_draw_focus (widget);
if (node == drag_highlight)
{
&width, NULL);
gtk_paint_focus (widget->style,
tree_view->priv->bin_window,
+ GTK_WIDGET_STATE (widget),
NULL,
widget,
"treeview-drop-indicator",
0, BACKGROUND_FIRST_PIXEL (tree_view, tree, node),
- width - 1, BACKGROUND_HEIGHT (node) - 1);
+ width, BACKGROUND_HEIGHT (node));
break;
}
node = tree->parent_node;
tree = tree->parent_tree;
if (tree == NULL)
- /* we've run out of tree. It's okay to return though, as
- * we'd only break out of the while loop below. */
- return TRUE;
+ /* we should go to done to free some memory */
+ goto done;
has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
&iter,
&parent_iter);
}
while (y_offset < event->area.height);
+ done:
if (cursor_path)
gtk_tree_path_free (cursor_path);
if (drag_dest_path)
gtk_tree_path_free (drag_dest_path);
- return TRUE;
+ return FALSE;
}
static gboolean
if (event->window == tree_view->priv->bin_window)
return gtk_tree_view_bin_expose (widget, event);
+ else if (event->window == tree_view->priv->header_window)
+ {
+ GList *list;
+
+ for (list = tree_view->priv->columns; list != NULL; list = list->next)
+ {
+ GtkTreeViewColumn *column = list->data;
+
+ if (column->visible)
+ gtk_container_propagate_expose (GTK_CONTAINER (tree_view),
+ column->button,
+ event);
+ }
+ }
return TRUE;
}
GdkEventKey *event)
{
GtkTreeView *tree_view = (GtkTreeView *) widget;
- gint retval;
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
{
return TRUE;
}
- retval = (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
-
- if (! retval)
- gtk_tree_view_interactive_search (tree_view, event);
-
- return retval;
+ return (* GTK_WIDGET_CLASS (parent_class)->key_press_event) (widget, event);
}
/* FIXME Is this function necessary? Can I get an enter_notify event
return TRUE;
/* find the node internally */
- new_y = ((gint)event->y<TREE_VIEW_HEADER_HEIGHT (tree_view))?TREE_VIEW_HEADER_HEIGHT (tree_view):(gint)event->y;
-
- _gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, new_y),
- &tree,
- &node);
+ new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
+ if (new_y < 0)
+ 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, new_y);
+ do_prelight (tree_view, tree, node, event->x, event->y);
if (tree_view->priv->prelight_node)
gtk_tree_view_queue_draw_node (tree_view,
gtk_tree_view_leave_notify (GtkWidget *widget,
GdkEventCrossing *event)
{
+ GtkWidget *search_dialog;
GtkTreeView *tree_view;
g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE);
+ if (event->mode == GDK_CROSSING_GRAB)
+ return TRUE;
tree_view = GTK_TREE_VIEW (widget);
if (tree_view->priv->prelight_node)
NULL);
ensure_unprelighted (tree_view);
-
+
+ /* destroy interactive search dialog */
+ search_dialog = gtk_object_get_data (GTK_OBJECT (widget),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
+ if (search_dialog)
+ gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
+
return TRUE;
}
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
gtk_widget_queue_draw (widget);
- GTK_TREE_VIEW (widget)->priv->in_extended_selection = FALSE;
- GTK_TREE_VIEW (widget)->priv->in_free_motion = FALSE;
/* destroy interactive search dialog */
- search_dialog = gtk_object_get_data (GTK_OBJECT (widget), "search-dialog");
+ search_dialog = gtk_object_get_data (GTK_OBJECT (widget),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
if (search_dialog)
- gtk_tree_view_search_dialog_destroy (search_dialog,
- GTK_TREE_VIEW (widget));
+ gtk_tree_view_search_dialog_destroy (search_dialog, GTK_TREE_VIEW (widget));
return FALSE;
}
-/* Drag-and-drop */
-
-static void
-set_source_row (GdkDragContext *context,
- GtkTreeModel *model,
- GtkTreePath *source_row)
-{
- g_object_set_data_full (G_OBJECT (context),
- "gtk-tree-view-source-row",
- source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
- (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
-}
-
-static GtkTreePath*
-get_source_row (GdkDragContext *context)
-{
- GtkTreeRowReference *ref =
- g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
-
- if (ref)
- return gtk_tree_row_reference_get_path (ref);
- else
- return NULL;
-}
-
-
-static void
-set_dest_row (GdkDragContext *context,
- GtkTreeModel *model,
- GtkTreePath *dest_row)
-{
- 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));
-}
-
-static GtkTreePath*
-get_dest_row (GdkDragContext *context)
-{
- GtkTreeRowReference *ref =
- g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
-
- if (ref)
- return gtk_tree_row_reference_get_path (ref);
- else
- return NULL;
-}
+/* Incremental Reflow
+ */
-/* Get/set whether drag_motion requested the drag data and
- * drag_data_received should thus not actually insert the data,
- * since the data doesn't result from a drop.
+/* Returns TRUE if it updated the size
*/
-static void
-set_status_pending (GdkDragContext *context,
- GdkDragAction suggested_action)
+static gboolean
+validate_row (GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkRBNode *node,
+ GtkTreeIter *iter,
+ GtkTreePath *path)
{
- g_object_set_data (G_OBJECT (context),
- "gtk-tree-view-status-pending",
- GINT_TO_POINTER (suggested_action));
-}
+ GtkTreeViewColumn *column;
+ GList *list;
+ gint height = 0;
+ gint horizontal_separator;
+ gint depth = gtk_tree_path_get_depth (path);
+ gboolean retval = FALSE;
-static GdkDragAction
-get_status_pending (GdkDragContext *context)
-{
- return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
- "gtk-tree-view-status-pending"));
-}
-static TreeViewDragInfo*
-get_info (GtkTreeView *tree_view)
-{
- return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
-}
+ /* double check the row needs validating */
+ if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) &&
+ ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ return FALSE;
-static void
-clear_source_info (TreeViewDragInfo *di)
-{
- if (di->source_target_list)
- gtk_target_list_unref (di->source_target_list);
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "horizontal_separator", &horizontal_separator,
+ NULL);
- if (di->row_draggable_closure)
- g_closure_unref (di->row_draggable_closure);
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ gint tmp_width;
+ gint tmp_height;
- di->source_target_list = NULL;
- di->row_draggable_closure = NULL;
-}
+ column = list->data;
-static void
-clear_dest_info (TreeViewDragInfo *di)
-{
- if (di->location_droppable_closure)
- g_closure_unref (di->location_droppable_closure);
+ if (! column->visible)
+ continue;
- if (di->dest_target_list)
- gtk_target_list_unref (di->dest_target_list);
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) && !column->dirty)
+ continue;
- di->location_droppable_closure = NULL;
- di->dest_target_list = NULL;
-}
+ if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+ continue;
-static void
-destroy_info (TreeViewDragInfo *di)
-{
- clear_source_info (di);
- clear_dest_info (di);
- g_free (di);
-}
+ gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
+ node->children?TRUE:FALSE);
+ gtk_tree_view_column_cell_get_size (column,
+ NULL, NULL, NULL,
+ &tmp_width, &tmp_height);
+ height = MAX (height, tmp_height);
-static TreeViewDragInfo*
-ensure_info (GtkTreeView *tree_view)
-{
- TreeViewDragInfo *di;
+ if (gtk_tree_view_is_expander_column (tree_view, column) && TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ tmp_width = tmp_width + horizontal_separator + depth * tree_view->priv->tab_offset;
+ else
+ tmp_width = tmp_width + horizontal_separator;
- di = get_info (tree_view);
+ if (tmp_width > column->requested_width)
+ {
+ retval = TRUE;
+ column->requested_width = tmp_width;
+ }
+ }
- if (di == NULL)
+ if (height != GTK_RBNODE_GET_HEIGHT (node))
{
- di = g_new0 (TreeViewDragInfo, 1);
-
- g_object_set_data_full (G_OBJECT (tree_view),
- "gtk-tree-view-drag-info",
- di,
- (GDestroyNotify) destroy_info);
+ retval = TRUE;
+ _gtk_rbtree_node_set_height (tree, node, height);
}
+ _gtk_rbtree_node_mark_valid (tree, node);
- return di;
+ return retval;
}
+
static void
-remove_info (GtkTreeView *tree_view)
+validate_visible_area (GtkTreeView *tree_view)
+{
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ GtkRBTree *tree;
+ GtkRBNode *node;
+ gint y, height, offset;
+ gboolean validated_area = FALSE;
+ gboolean size_changed = FALSE;
+
+ if (tree_view->priv->tree == NULL)
+ return;
+
+ if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
+ return;
+
+ height = GTK_WIDGET (tree_view)->allocation.height - TREE_VIEW_HEADER_HEIGHT (tree_view);
+
+ y = TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, TREE_VIEW_HEADER_HEIGHT (tree_view));
+
+ offset = _gtk_rbtree_find_offset (tree_view->priv->tree, y,
+ &tree, &node);
+ if (node == NULL)
+ {
+ path = gtk_tree_path_new_root ();
+ _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+ }
+ else
+ {
+ path = _gtk_tree_view_find_path (tree_view, tree, node);
+ height += offset;
+ }
+
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
+ do
+ {
+ gint old_height;
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ validated_area = TRUE;
+ if (validate_row (tree_view, tree, node, &iter, path))
+ size_changed = TRUE;
+ }
+ height -= GTK_RBNODE_GET_HEIGHT (node);
+
+ if (node->children)
+ {
+ GtkTreeIter parent = iter;
+ gboolean has_child;
+
+ tree = node->children;
+ node = tree->root;
+
+ g_assert (node != tree->nil);
+
+ while (node->left != tree->nil)
+ node = node->left;
+ has_child = gtk_tree_model_iter_children (tree_view->priv->model,
+ &iter,
+ &parent);
+ TREE_VIEW_INTERNAL_ASSERT_VOID (has_child);
+ gtk_tree_path_append_index (path, 0);
+ }
+ else
+ {
+ gboolean done = FALSE;
+ do
+ {
+ node = _gtk_rbtree_next (tree, node);
+ if (node != NULL)
+ {
+ gboolean has_next = gtk_tree_model_iter_next (tree_view->priv->model, &iter);
+ done = TRUE;
+
+ /* Sanity Check! */
+ TREE_VIEW_INTERNAL_ASSERT_VOID (has_next);
+ }
+ else
+ {
+ GtkTreeIter parent_iter = iter;
+ gboolean has_parent;
+
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ if (tree == NULL)
+ break;
+ has_parent = gtk_tree_model_iter_parent (tree_view->priv->model,
+ &iter,
+ &parent_iter);
+
+ /* Sanity check */
+ TREE_VIEW_INTERNAL_ASSERT_VOID (has_parent);
+ }
+ }
+ while (!done);
+ }
+ }
+ while (node && height > 0);
+
+ if (size_changed)
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ if (validated_area)
+ gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+}
+
+/* Our strategy for finding nodes to validate is a little convoluted. We find
+ * the left-most uninvalidated node. We then try walking right, validating
+ * nodes. Once we find a valid node, we repeat the previous process of finding
+ * the first invalid node.
+ */
+
+static gboolean
+validate_rows_handler (GtkTreeView *tree_view)
+{
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+ gboolean validated_area = FALSE;
+ gint retval = TRUE;
+ GtkTreePath *path = NULL;
+ GtkTreeIter iter;
+ gint i = 0;
+ g_assert (tree_view);
+ g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
+
+ GDK_THREADS_ENTER ();
+
+ do
+ {
+
+ if (! GTK_RBNODE_FLAG_SET (tree_view->priv->tree->root, GTK_RBNODE_DESCENDANTS_INVALID))
+ {
+ retval = FALSE;
+ goto done;
+ }
+
+ if (path != NULL)
+ {
+ node = _gtk_rbtree_next (tree, node);
+ if (node != NULL)
+ {
+ TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_next (tree_view->priv->model, &iter), FALSE);
+ gtk_tree_path_next (path);
+ }
+ else
+ {
+ gtk_tree_path_free (path);
+ path = NULL;
+ }
+ }
+
+ if (path == NULL)
+ {
+ tree = tree_view->priv->tree;
+ node = tree_view->priv->tree->root;
+
+ g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID));
+
+ do
+ {
+ if (node->left != tree->nil &&
+ GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID))
+ {
+ node = node->left;
+ }
+ else if (node->right != tree->nil &&
+ GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID))
+ {
+ node = node->right;
+ }
+ else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))
+ {
+ break;
+ }
+ else if (node->children != NULL)
+ {
+ tree = node->children;
+ node = tree->root;
+ }
+ else
+ /* RBTree corruption! All bad */
+ g_assert_not_reached ();
+ }
+ while (TRUE);
+ 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;
+ i++;
+ }
+ while (i < GTK_TREE_VIEW_NUM_ROWS_PER_IDLE);
+
+ done:
+ if (path) gtk_tree_path_free (path);
+ if (validated_area)
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ if (! retval)
+ tree_view->priv->validate_rows_timer = 0;
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+static gboolean
+presize_handler_callback (gpointer data)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (data);
+
+ GDK_THREADS_ENTER ();
+
+ if (tree_view->priv->mark_rows_col_dirty)
+ {
+ if (tree_view->priv->tree)
+ _gtk_rbtree_column_invalid (tree_view->priv->tree);
+ tree_view->priv->mark_rows_col_dirty = FALSE;
+ }
+ validate_visible_area (tree_view);
+ tree_view->priv->presize_handler_timer = 0;
+
+ GDK_THREADS_LEAVE ();
+
+ return FALSE;
+}
+
+static void
+install_presize_handler (GtkTreeView *tree_view)
+{
+ if (! tree_view->priv->presize_handler_timer)
+ {
+ tree_view->priv->presize_handler_timer =
+ g_idle_add_full (GTK_PRIORITY_RESIZE - 2, presize_handler_callback, tree_view, NULL);
+ }
+ if (! tree_view->priv->validate_rows_timer)
+ {
+ tree_view->priv->validate_rows_timer =
+ g_idle_add_full (GTK_TREE_VIEW_PRIORITY_VALIDATE, (GSourceFunc) validate_rows_handler, tree_view, NULL);
+ }
+}
+
+
+void
+_gtk_tree_view_install_mark_rows_col_dirty (GtkTreeView *tree_view)
+{
+ tree_view->priv->mark_rows_col_dirty = TRUE;
+
+ install_presize_handler (tree_view);
+}
+
+/* Drag-and-drop */
+
+static void
+set_source_row (GdkDragContext *context,
+ GtkTreeModel *model,
+ GtkTreePath *source_row)
+{
+ g_object_set_data_full (G_OBJECT (context),
+ "gtk-tree-view-source-row",
+ source_row ? gtk_tree_row_reference_new (model, source_row) : NULL,
+ (GDestroyNotify) (source_row ? gtk_tree_row_reference_free : NULL));
+}
+
+static GtkTreePath*
+get_source_row (GdkDragContext *context)
+{
+ GtkTreeRowReference *ref =
+ g_object_get_data (G_OBJECT (context), "gtk-tree-view-source-row");
+
+ if (ref)
+ return gtk_tree_row_reference_get_path (ref);
+ else
+ return NULL;
+}
+
+
+static void
+set_dest_row (GdkDragContext *context,
+ GtkTreeModel *model,
+ GtkTreePath *dest_row)
+{
+ 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));
+}
+
+static GtkTreePath*
+get_dest_row (GdkDragContext *context)
+{
+ GtkTreeRowReference *ref =
+ g_object_get_data (G_OBJECT (context), "gtk-tree-view-dest-row");
+
+ if (ref)
+ return gtk_tree_row_reference_get_path (ref);
+ else
+ return NULL;
+}
+
+/* Get/set whether drag_motion requested the drag data and
+ * drag_data_received should thus not actually insert the data,
+ * since the data doesn't result from a drop.
+ */
+static void
+set_status_pending (GdkDragContext *context,
+ GdkDragAction suggested_action)
+{
+ g_object_set_data (G_OBJECT (context),
+ "gtk-tree-view-status-pending",
+ GINT_TO_POINTER (suggested_action));
+}
+
+static GdkDragAction
+get_status_pending (GdkDragContext *context)
+{
+ return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (context),
+ "gtk-tree-view-status-pending"));
+}
+
+static TreeViewDragInfo*
+get_info (GtkTreeView *tree_view)
+{
+ return g_object_get_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info");
+}
+
+static void
+clear_source_info (TreeViewDragInfo *di)
+{
+ if (di->source_target_list)
+ gtk_target_list_unref (di->source_target_list);
+
+ di->source_target_list = NULL;
+}
+
+static void
+clear_dest_info (TreeViewDragInfo *di)
+{
+ if (di->dest_target_list)
+ gtk_target_list_unref (di->dest_target_list);
+
+ di->dest_target_list = NULL;
+}
+
+static void
+destroy_info (TreeViewDragInfo *di)
+{
+ clear_source_info (di);
+ clear_dest_info (di);
+ g_free (di);
+}
+
+static TreeViewDragInfo*
+ensure_info (GtkTreeView *tree_view)
+{
+ TreeViewDragInfo *di;
+
+ di = get_info (tree_view);
+
+ if (di == NULL)
+ {
+ di = g_new0 (TreeViewDragInfo, 1);
+
+ g_object_set_data_full (G_OBJECT (tree_view),
+ "gtk-tree-view-drag-info",
+ di,
+ (GDestroyNotify) destroy_info);
+ }
+
+ return di;
+}
+
+static void
+remove_info (GtkTreeView *tree_view)
{
g_object_set_data (G_OBJECT (tree_view), "gtk-tree-view-drag-info", NULL);
}
gtk_tree_view_scroll_to_cell (tree_view,
path,
column,
+ TRUE,
0.5, 0.5);
gtk_tree_path_free (path);
gboolean result = FALSE;
GDK_THREADS_ENTER ();
-
+
gtk_tree_view_get_drag_dest_row (tree_view,
&dest_path,
&pos);
{
if (dest_path)
gtk_tree_path_free (dest_path);
-
+
result = TRUE;
}
-
+
GDK_THREADS_LEAVE ();
return result;
gint button;
gint cell_x, cell_y;
GtkTreeModel *model;
+ gboolean retval = FALSE;
di = get_info (tree_view);
if (di == NULL)
- return FALSE;
+ goto out;
if (tree_view->priv->pressed_button < 0)
- return FALSE;
+ goto out;
if (!gtk_drag_check_threshold (GTK_WIDGET (tree_view),
tree_view->priv->press_start_x,
tree_view->priv->press_start_y,
event->x, event->y))
- return FALSE;
+ goto out;
model = gtk_tree_view_get_model (tree_view);
if (model == NULL)
- return FALSE;
+ goto out;
button = tree_view->priv->pressed_button;
tree_view->priv->pressed_button = -1;
gtk_tree_view_get_path_at_pos (tree_view,
- tree_view->priv->bin_window,
tree_view->priv->press_start_x,
tree_view->priv->press_start_y,
&path,
&cell_y);
if (path == NULL)
- return FALSE;
+ goto out;
- /* FIXME if the path doesn't match the row_draggable predicate,
- * return FALSE and free path
- */
+ if (!GTK_IS_TREE_DRAG_SOURCE (model) ||
+ !gtk_tree_drag_source_row_draggable (GTK_TREE_DRAG_SOURCE (model),
+ path))
+ goto out;
/* FIXME Check whether we're a start button, if not return FALSE and
* free path
*/
+ /* Now we can begin the drag */
+
+ retval = TRUE;
+
context = gtk_drag_begin (GTK_WIDGET (tree_view),
di->source_target_list,
di->source_actions,
}
set_source_row (context, model, path);
- gtk_tree_path_free (path);
- return TRUE;
+ out:
+ if (path)
+ gtk_tree_path_free (path);
+
+ return retval;
}
/* If drag_data_get does nothing, try providing row data. */
if (selection_data->target == gdk_atom_intern ("GTK_TREE_MODEL_ROW", FALSE))
{
- gtk_selection_data_set_tree_row (selection_data,
- model,
- source_row);
+ gtk_tree_set_row_drag_data (selection_data,
+ model,
+ source_row);
}
done:
if (!set_destination_row (tree_view, context, x, y, &suggested_action, &target))
return FALSE;
- // gtk_tree_view_ensure_scroll_timeout (tree_view);
-
gtk_tree_view_get_drag_dest_row (tree_view, &path, &pos);
if (path == NULL)
if (suggested_action)
{
- GtkTreeModel *src_model = NULL;
- GtkTreePath *src_path = NULL;
-
- if (!gtk_selection_data_get_tree_row (selection_data,
- &src_model,
- &src_path))
- suggested_action = 0;
-
- if (suggested_action)
- {
- if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
- src_model,
- src_path,
- path))
- suggested_action = 0;
-
- gtk_tree_path_free (src_path);
- }
+ if (!gtk_tree_drag_dest_row_drop_possible (GTK_TREE_DRAG_DEST (model),
+ path,
+ selection_data))
+ suggested_action = 0;
}
gdk_drag_status (context, suggested_action, time);
while (last_column)
{
if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (last_column->data)->button) &&
+ GTK_TREE_VIEW_COLUMN (last_column->data)->clickable &&
+ GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
GTK_TREE_VIEW_COLUMN (last_column->data)->visible)
break;
last_column = last_column->prev;
while (first_column)
{
if (GTK_WIDGET_CAN_FOCUS (GTK_TREE_VIEW_COLUMN (first_column->data)->button) &&
+ GTK_TREE_VIEW_COLUMN (first_column->data)->clickable &&
+ GTK_TREE_VIEW_COLUMN (last_column->data)->reorderable &&
GTK_TREE_VIEW_COLUMN (first_column->data)->visible)
break;
first_column = first_column->next;
return (focus_child != NULL);
}
-/* We make the assumption that if container->focus_child != NULL, the focus must
- * be in the header. For now, this is accurate. It may not be in the future.
- */
-
-/* The sordid relationship between focus_column and scroll_column:
- *
- * The focus_column represents the column that currently has keyboard focus, and
- * is used when navigating columns by keyboard. scroll_column is used for
- * handling scrolling by keyboard, such that in cases.
- */
static gint
gtk_tree_view_focus (GtkWidget *widget,
GtkDirectionType direction)
focus_child = container->focus_child;
+ gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget));
/* Case 1. Headers currently have focus. */
if (focus_child)
{
gtk_tree_view_adjustment_changed (NULL, tree_view);
}
-static void
-gtk_tree_view_real_begin_extended_selection (GtkTreeView *tree_view)
-{
- tree_view->priv->in_extended_selection = TRUE;
-}
-
-static void
-gtk_tree_view_real_end_extended_selection (GtkTreeView *tree_view)
-{
- tree_view->priv->in_extended_selection = FALSE;
-}
-
-static void
-gtk_tree_view_real_begin_free_motion (GtkTreeView *tree_view)
-{
- tree_view->priv->in_free_motion = TRUE;
-}
-
-static void
-gtk_tree_view_real_end_free_motion (GtkTreeView *tree_view)
-{
- tree_view->priv->in_free_motion = FALSE;
-}
static void
gtk_tree_view_real_move_cursor (GtkTreeView *tree_view,
if (tree_view->priv->tree == NULL)
return;
-
+ gtk_tree_view_stop_editing (tree_view);
GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
gtk_widget_grab_focus (GTK_WIDGET (tree_view));
}
}
+static void
+gtk_tree_view_put (GtkTreeView *tree_view,
+ GtkWidget *child_widget,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GtkTreeViewChild *child;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_WIDGET (child_widget));
+
+ child = g_new (GtkTreeViewChild, 1);
+
+ child->widget = child_widget;
+ child->x = x;
+ child->y = y;
+ child->width = width;
+ child->height = height;
+
+ tree_view->priv->children = g_list_append (tree_view->priv->children, child);
+
+ if (GTK_WIDGET_REALIZED (tree_view))
+ gtk_widget_set_parent_window (child->widget, tree_view->priv->bin_window);
+
+ gtk_widget_set_parent (child_widget, GTK_WIDGET (tree_view));
+}
+
+void
+_gtk_tree_view_child_move_resize (GtkTreeView *tree_view,
+ GtkWidget *widget,
+ gint x,
+ gint y,
+ gint width,
+ gint height)
+{
+ GtkTreeViewChild *child = NULL;
+ GList *list;
+ GdkRectangle allocation;
+
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ for (list = tree_view->priv->children; list; list = list->next)
+ {
+ if (((GtkTreeViewChild *)list->data)->widget == widget)
+ {
+ child = list->data;
+ break;
+ }
+ }
+ if (child == NULL)
+ return;
+
+ allocation.x = child->x = x;
+ allocation.y = child->y = y;
+ allocation.width = child->width = width;
+ allocation.height = child->height = height;
+
+ if (GTK_WIDGET_REALIZED (widget))
+ gtk_widget_size_allocate (widget, &allocation);
+}
+
+
/* TreeModel Callbacks
*/
static void
-gtk_tree_view_range_changed (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- GtkTreePath *end_path,
- GtkTreeIter *end_iter,
- gpointer data)
+gtk_tree_view_row_changed (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
{
GtkTreeView *tree_view = (GtkTreeView *)data;
GtkRBTree *tree;
GtkRBNode *node;
- gint height;
- gboolean dirty_marked;
gboolean free_path = FALSE;
gint vertical_separator;
-
+ GList *list;
g_return_if_fail (path != NULL || iter != NULL);
if (tree == NULL)
goto done;
- dirty_marked = gtk_tree_view_discover_dirty_iter (tree_view,
- iter,
- gtk_tree_path_get_depth (path),
- &height,
- node);
-
- if (GTK_RBNODE_GET_HEIGHT (node) != height + vertical_separator)
+ _gtk_rbtree_node_mark_invalid (tree, node);
+ for (list = tree_view->priv->columns; list; list = list->next)
{
- _gtk_rbtree_node_set_height (tree, node, height + vertical_separator);
- gtk_widget_queue_resize (GTK_WIDGET (data));
- goto done;
+ GtkTreeViewColumn *column;
+
+ column = list->data;
+ if (! column->visible)
+ continue;
+
+ if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
+ {
+ gtk_tree_view_column_cell_set_dirty (column);
+ }
}
- if (dirty_marked)
- gtk_widget_queue_resize (GTK_WIDGET (data));
- else
- gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
+ install_presize_handler (tree_view);
done:
if (free_path)
}
static void
-gtk_tree_view_inserted (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
+gtk_tree_view_row_inserted (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
{
GtkTreeView *tree_view = (GtkTreeView *) data;
gint *indices;
GtkRBTree *tmptree, *tree;
GtkRBNode *tmpnode = NULL;
- gint max_height;
gint depth;
gint i = 0;
gboolean free_path = FALSE;
- if (tree_view->priv->tree == NULL)
- tree_view->priv->tree = _gtk_rbtree_new ();
-
- tmptree = tree = tree_view->priv->tree;
g_return_if_fail (path != NULL || iter != NULL);
if (path == NULL)
else if (iter == NULL)
gtk_tree_model_get_iter (model, iter, path);
+ if (tree_view->priv->tree == NULL)
+ tree_view->priv->tree = _gtk_rbtree_new ();
+
+ tmptree = tree = tree_view->priv->tree;
+
/* Update all row-references */
gtk_tree_row_reference_inserted (G_OBJECT (data), path);
-
depth = gtk_tree_path_get_depth (path);
indices = gtk_tree_path_get_indices (path);
GtkTreePath *tmppath = _gtk_tree_view_find_path (tree_view,
tree,
tmpnode);
- gtk_tree_view_has_child_toggled (model, tmppath, NULL, data);
+ gtk_tree_view_row_has_child_toggled (model, tmppath, NULL, data);
gtk_tree_path_free (tmppath);
goto done;
}
/* ref the node */
gtk_tree_model_ref_node (tree_view->priv->model, iter);
- max_height = gtk_tree_view_insert_iter_height (tree_view,
- tree,
- iter,
- depth);
if (indices[depth - 1] == 0)
{
tmpnode = _gtk_rbtree_find_count (tree, 1);
- _gtk_rbtree_insert_before (tree, tmpnode, max_height);
+ _gtk_rbtree_insert_before (tree, tmpnode, 0, FALSE);
}
else
{
tmpnode = _gtk_rbtree_find_count (tree, indices[depth - 1]);
- _gtk_rbtree_insert_after (tree, tmpnode, max_height);
+ _gtk_rbtree_insert_after (tree, tmpnode, 0, FALSE);
}
-
- _gtk_tree_view_update_size (tree_view);
+ install_presize_handler (tree_view);
done:
if (free_path)
}
static void
-gtk_tree_view_has_child_toggled (GtkTreeModel *model,
- GtkTreePath *path,
- GtkTreeIter *iter,
- gpointer data)
+gtk_tree_view_row_has_child_toggled (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
{
GtkTreeView *tree_view = (GtkTreeView *)data;
GtkTreeIter real_iter;
if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
{
GTK_TREE_VIEW_COLUMN (list->data)->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (GTK_TREE_VIEW_COLUMN (list->data));
break;
}
}
}
static void
-gtk_tree_view_deleted (GtkTreeModel *model,
- GtkTreePath *path,
- gpointer data)
+gtk_tree_view_row_deleted (GtkTreeModel *model,
+ GtkTreePath *path,
+ gpointer data)
{
GtkTreeView *tree_view = (GtkTreeView *)data;
GtkRBTree *tree;
GtkRBNode *node;
GList *list;
+ gint selection_changed;
g_return_if_fail (path != NULL);
+ gtk_tree_row_reference_deleted (G_OBJECT (data), path);
+
if (_gtk_tree_view_find_node (tree_view, path, &tree, &node))
return;
if (tree == NULL)
return;
- gtk_tree_row_reference_deleted (G_OBJECT (data), path);
-
/* Change the selection */
- if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED))
- g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
+ selection_changed = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
for (list = tree_view->priv->columns; list; list = list->next)
if (((GtkTreeViewColumn *)list->data)->visible &&
((GtkTreeViewColumn *)list->data)->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- ((GtkTreeViewColumn *)list->data)->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty ((GtkTreeViewColumn *)list->data);
/* Ensure we don't have a dangling pointer to a dead node */
ensure_unprelighted (tree_view);
GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
tree_view->priv->expanded_collapsed_node = NULL;
}
-
+
if (tree_view->priv->destroy_count_func)
{
gint child_count = 0;
_gtk_rbtree_remove_node (tree, node);
}
- _gtk_tree_view_update_size (GTK_TREE_VIEW (data));
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+
+ if (selection_changed)
+ g_signal_emit_by_name (G_OBJECT (tree_view->priv->selection), "changed");
}
static void
-gtk_tree_view_reordered (GtkTreeModel *model,
- GtkTreePath *parent,
- GtkTreeIter *iter,
- gint *new_order,
- gpointer data)
+gtk_tree_view_rows_reordered (GtkTreeModel *model,
+ GtkTreePath *parent,
+ GtkTreeIter *iter,
+ gint *new_order,
+ gpointer data)
{
GtkTreeView *tree_view = GTK_TREE_VIEW (data);
GtkRBTree *tree;
}
-/* Internal tree functions
- */
-
-
-static void
-gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeViewColumn *column,
- gint *x1,
- gint *x2)
-{
- GtkTreeViewColumn *tmp_column = NULL;
- gint total_width;
- GList *list;
-
- if (x1)
- *x1 = 0;
-
- if (x2)
- *x2 = 0;
-
- total_width = 0;
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- tmp_column = list->data;
-
- if (tmp_column == column)
- break;
-
- if (tmp_column->visible)
- total_width += tmp_column->width;
- }
-
- if (tmp_column != column)
- {
- g_warning (G_STRLOC": passed-in column isn't in the tree");
- return;
- }
-
- if (x1)
- *x1 = total_width;
-
- if (x2)
- {
- if (column->visible)
- *x2 = total_width + column->width;
- else
- *x2 = total_width; /* width of 0 */
- }
-}
-
+/* Internal tree functions
+ */
+
+
static void
-gtk_tree_view_get_cell_xrange (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeViewColumn *column,
- gint *x1,
- gint *x2)
+gtk_tree_view_get_background_xrange (GtkTreeView *tree_view,
+ GtkRBTree *tree,
+ GtkTreeViewColumn *column,
+ gint *x1,
+ gint *x2)
{
GtkTreeViewColumn *tmp_column = NULL;
gint total_width;
return;
}
- /* Remember we're getting the cell range, i.e. the cell_area passed
- * to the cell renderer.
- */
-
- if (gtk_tree_view_is_expander_column (tree_view, column))
- total_width += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
-
if (x1)
*x1 = total_width;
if (x2)
{
if (column->visible)
- *x2 = total_width + column->displayed_width;
+ *x2 = total_width + column->width;
else
*x2 = total_width; /* width of 0 */
}
}
-
static void
gtk_tree_view_get_arrow_xrange (GtkTreeView *tree_view,
+ GtkRBTree *tree,
gint *x1,
gint *x2)
{
GList *list;
GtkTreeViewColumn *tmp_column = NULL;
gint total_width;
+ gboolean indent_expanders;
total_width = 0;
for (list = tree_view->priv->columns; list; list = list->next)
total_width += tmp_column->width;
}
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "indent_expanders", &indent_expanders,
+ NULL);
+
+ if (indent_expanders)
+ x_offset += tree_view->priv->tab_offset * _gtk_rbtree_get_depth (tree);
+
if (x1)
*x1 = x_offset;
}
}
-static gint
-gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth)
-{
- GtkTreeViewColumn *column;
- GList *list;
- gint max_height = 0;
- gint vertical_separator;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
-
- /* do stuff with node */
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- gint height = 0, width = 0;
- column = list->data;
-
- if (!column->visible)
- continue;
-
- if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
- continue;
-
- gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
- gtk_tree_model_iter_has_child (tree_view->priv->model, iter),
- FALSE);
-
- gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
- max_height = MAX (max_height, vertical_separator + height);
-
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS (tree_view))
- _gtk_tree_view_column_set_width (column,
- MAX (column->width, depth * tree_view->priv->tab_offset + width));
- else
- _gtk_tree_view_column_set_width (column,
- MAX (column->width, width));
- }
- return max_height;
-}
-
static void
gtk_tree_view_build_tree (GtkTreeView *tree_view,
GtkRBTree *tree,
GtkTreeIter *iter,
gint depth,
- gboolean recurse,
- gboolean calc_bounds)
+ gboolean recurse)
{
GtkRBNode *temp = NULL;
- gint max_height;
do
{
- max_height = 0;
- if (calc_bounds)
- max_height = gtk_tree_view_insert_iter_height (tree_view,
- tree,
- iter,
- depth);
-
gtk_tree_model_ref_node (tree_view->priv->model, iter);
- temp = _gtk_rbtree_insert_after (tree, temp, max_height);
+ temp = _gtk_rbtree_insert_after (tree, temp, 0, FALSE);
if (recurse)
{
GtkTreeIter child;
temp->children = _gtk_rbtree_new ();
temp->children->parent_tree = tree;
temp->children->parent_node = temp;
- gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse, calc_bounds);
+ gtk_tree_view_build_tree (tree_view, temp->children, &child, depth + 1, recurse);
}
}
if (gtk_tree_model_iter_has_child (tree_view->priv->model, iter))
while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
}
-static void
-gtk_tree_view_calc_size (GtkTreeView *tree_view,
- GtkRBTree *tree,
- GtkTreeIter *iter,
- gint depth)
-{
- GtkRBNode *temp;
- GtkTreeIter child;
- GList *list;
- GtkTreeViewColumn *column;
- gint max_height;
- gint vertical_separator;
-
- TREE_VIEW_INTERNAL_ASSERT_VOID (tree != NULL);
-
- gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
-
- temp = tree->root;
- while (temp->left != tree->nil)
- temp = temp->left;
-
- do
- {
- max_height = 0;
- /* Do stuff with node */
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- gint height = 0, width = 0;
- column = list->data;
-
- if (!column->visible)
- continue;
-
- gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
- GTK_RBNODE_FLAG_SET (temp, GTK_RBNODE_IS_PARENT),
- temp->children?TRUE:FALSE);
- gtk_tree_view_column_cell_get_size (column, NULL, NULL, NULL, &width, &height);
- max_height = MAX (max_height, vertical_separator + height);
-
- /* FIXME: I'm getting the width of all nodes here. )-: */
- if (column->dirty == FALSE)
- continue;
-
- if (column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
- {
- continue;
- }
- if (gtk_tree_view_is_expander_column (tree_view, column) &&
- TREE_VIEW_DRAW_EXPANDERS (tree_view))
- _gtk_tree_view_column_set_width (column,
- MAX (column->width, depth * tree_view->priv->tab_offset + width));
- else
- _gtk_tree_view_column_set_width (column, MAX (column->width, width));
- }
-
- _gtk_rbtree_node_set_height (tree, temp, max_height);
-
- if (temp->children != NULL &&
- gtk_tree_model_iter_children (tree_view->priv->model, &child, iter))
- gtk_tree_view_calc_size (tree_view, temp->children, &child, depth + 1);
- temp = _gtk_rbtree_next (tree, temp);
- }
- while (gtk_tree_model_iter_next (tree_view->priv->model, iter));
-}
-
+/* If height is non-NULL, then we set it to be the new height. if it's all
+ * dirty, then height is -1. We know we'll remeasure dirty rows, anyways.
+ */
static gboolean
gtk_tree_view_discover_dirty_iter (GtkTreeView *tree_view,
GtkTreeIter *iter,
GList *list;
gboolean retval = FALSE;
gint tmpheight;
-
+ gint horizontal_separator;
+
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "horizontal_separator", &horizontal_separator,
+ NULL);
+
+
if (height)
- *height = 0;
+ *height = -1;
for (list = tree_view->priv->columns; list; list = list->next)
{
gint width;
column = list->data;
- if (column->dirty == TRUE || column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
+ if (column->dirty == TRUE)
+ continue;
+ if (height == NULL && column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
continue;
if (!column->visible)
continue;
-
+
gtk_tree_view_column_cell_set_cell_data (column, tree_view->priv->model, iter,
GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT),
node->children?TRUE:FALSE);
-
if (height)
{
gtk_tree_view_column_cell_get_size (column,
NULL, NULL, NULL,
&width, NULL);
}
+
if (gtk_tree_view_is_expander_column (tree_view, column) &&
TREE_VIEW_DRAW_EXPANDERS (tree_view))
{
- if (depth * tree_view->priv->tab_offset + width > column->width)
+ if (depth * tree_view->priv->tab_offset + horizontal_separator + width > column->requested_width)
{
- column->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (column);
retval = TRUE;
}
}
else
{
- if (width > column->width)
+ if (horizontal_separator + width > column->requested_width)
{
- column->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (column);
retval = TRUE;
}
}
gtk_tree_view_discover_dirty_iter (tree_view,
iter,
depth,
- FALSE,
+ NULL,
temp);
if (gtk_tree_model_iter_children (tree_view->priv->model, &child, iter) &&
temp->children != NULL)
}
-static void
-gtk_tree_view_check_dirty (GtkTreeView *tree_view)
-{
- GtkTreePath *path;
- gboolean dirty = FALSE;
- GList *list;
- GtkTreeViewColumn *column;
- GtkTreeIter iter;
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- if (column->dirty)
- {
- dirty = TRUE;
- if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
- {
- gint w = 1;
-
- if (column->button)
- w = MAX (w, column->button->requisition.width);
-
- _gtk_tree_view_column_set_width (column, w);
- }
- }
- }
-
- if (dirty == FALSE)
- return;
-
- if (tree_view->priv->model == NULL)
- return;
-
- path = gtk_tree_path_new_root ();
- if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
- {
- gtk_tree_view_calc_size (tree_view, tree_view->priv->tree, &iter, 1);
- _gtk_tree_view_update_size (tree_view);
- }
-
- gtk_tree_path_free (path);
-
- for (list = tree_view->priv->columns; list; list = list->next)
- {
- column = list->data;
- column->dirty = FALSE;
- }
-}
-
/* Make sure the node is visible vertically */
static void
gtk_tree_view_clamp_node_visible (GtkTreeView *tree_view,
}
-/* This function could be more efficient.
- * I'll optimize it if profiling seems to imply that
- * it's important
- */
+static void
+gtk_tree_view_clamp_column_visible (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column)
+{
+ if (column == NULL)
+ return;
+ if ((tree_view->priv->hadjustment->value + tree_view->priv->hadjustment->page_size) <
+ (column->button->allocation.x + column->button->allocation.width))
+ gtk_adjustment_set_value (tree_view->priv->hadjustment,
+ column->button->allocation.x + column->button->allocation.width -
+ tree_view->priv->hadjustment->page_size);
+ else if (tree_view->priv->hadjustment->value > column->button->allocation.x)
+ gtk_adjustment_set_value (tree_view->priv->hadjustment,
+ column->button->allocation.x);
+}
+
+/* This function could be more efficient. I'll optimize it if profiling seems
+ * to imply that it is important */
GtkTreePath *
_gtk_tree_view_find_path (GtkTreeView *tree_view,
GtkRBTree *tree,
{
GList *list;
+ if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IS_LIST))
+ return FALSE;
+
if (tree_view->priv->expander_column != NULL)
{
if (tree_view->priv->expander_column == column)
GtkRBNode *node;
gint retval;
+ if (!tree)
+ return FALSE;
+
node = tree->root;
while (node && node->left != tree->nil)
node = node->left;
send_event.button.axes = NULL;
send_event.button.state = 0;
send_event.button.button = 1;
- send_event.button.device = gdk_core_pointer;
+ send_event.button.device = gdk_device_get_core_pointer ();
send_event.button.x_root = 0;
send_event.button.y_root = 0;
if (clip_rect)
{
GdkRectangle new_rect;
-
+
gdk_rectangle_intersect (clip_rect, &rect, &new_rect);
-
+
gdk_window_invalidate_rect (tree_view->priv->bin_window, &new_rect, TRUE);
}
else
gint vertical_separator;
gint expander_size;
GtkExpanderStyle expander_style;
-
+
gtk_widget_style_get (GTK_WIDGET (tree_view),
"vertical_separator", &vertical_separator,
"expander_size", &expander_size,
widget = GTK_WIDGET (tree_view);
- gtk_tree_view_get_arrow_xrange (tree_view, &x_offset, NULL);
+ gtk_tree_view_get_arrow_xrange (tree_view, tree, &x_offset, NULL);
area.x = x_offset;
area.y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
expander_style);
}
-
-static void
-_gtk_tree_view_update_col_width (GtkTreeView *tree_view)
-{
- GList *list, *last_column;
- GtkTreeViewColumn *column;
- gint width = 0;
-
- for (last_column = 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)
- ;
-
- if (last_column == NULL)
- return;
-
- for (list = tree_view->priv->columns; list != last_column; list = list->next)
- {
- column = GTK_TREE_VIEW_COLUMN (list->data);
- if (! column->visible)
- continue;
-
- width += column->width;
- column->displayed_width = (CLAMP (column->width, (column->min_width!=-1)?column->min_width:column->width, (column->max_width!=-1)?column->max_width:column->width));
- }
- column = GTK_TREE_VIEW_COLUMN (last_column->data);
- column->displayed_width = MAX (GTK_WIDGET (tree_view)->allocation.width, tree_view->priv->width) - width;
-}
-
static void
gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view)
if (cursor_path == NULL)
{
- GtkTreePath *tmp_path = gtk_tree_path_new_root ();
- /* FIXME: Get the first one visible!!! */
- if (tree_view->priv->cursor)
- gtk_tree_row_reference_free (tree_view->priv->cursor);
+ cursor_path = gtk_tree_path_new_root ();
+ gtk_tree_row_reference_free (tree_view->priv->cursor);
+ tree_view->priv->cursor = NULL;
- tree_view->priv->cursor =
- gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view), tree_view->priv->model, tmp_path);
- cursor_path = tmp_path;
+ if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
+ else
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
}
-
- if (tree_view->priv->selection->type == GTK_TREE_SELECTION_SINGLE)
- gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
- else
- gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE);
gtk_tree_path_free (cursor_path);
+ if (tree_view->priv->focus_column == NULL)
+ {
+ GList *list;
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ if (GTK_TREE_VIEW_COLUMN (list->data)->visible)
+ {
+ tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data);
+ break;
+ }
+ }
+ }
}
static void
_gtk_rbtree_find_offset (tree_view->priv->tree, y, &cursor_tree, &cursor_node);
cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node);
g_return_if_fail (cursor_path != NULL);
- gtk_tree_view_real_set_cursor (tree_view,
- cursor_path,
- TRUE);
+ gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE);
}
static void
GtkRBTree *cursor_tree = NULL;
GtkRBNode *cursor_node = NULL;
GtkTreePath *cursor_path = NULL;
-
- g_print ("gtk_tree_view_move_cursor_left_right\n");
+ GtkTreeViewColumn *column;
+ GtkTreeIter iter;
+ GList *list;
+ gboolean found_column = FALSE;
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
else
return;
- _gtk_tree_view_find_node (tree_view, cursor_path,
- &cursor_tree, &cursor_node);
+ _gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node);
+ if (cursor_tree == NULL)
+ return;
+ if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path) == FALSE)
+ {
+ gtk_tree_path_free (cursor_path);
+ return;
+ }
gtk_tree_path_free (cursor_path);
+ list = tree_view->priv->columns;
+ if (tree_view->priv->focus_column)
+ {
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ if (list->data == tree_view->priv->focus_column)
+ break;
+ }
+ }
+
+ while (list)
+ {
+ column = list->data;
+ if (column->visible == FALSE)
+ goto loop_end;
+
+ gtk_tree_view_column_cell_set_cell_data (column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
+ cursor_node->children?TRUE:FALSE);
+ if (gtk_tree_view_column_cell_focus (column, count))
+ {
+ tree_view->priv->focus_column = column;
+ found_column = TRUE;
+ break;
+ }
+ loop_end:
+ if (count == 1)
+ list = list->next;
+ else
+ list = list->prev;
+ }
+ if (found_column)
+ {
+ gtk_tree_view_queue_draw_node (tree_view,
+ cursor_tree,
+ cursor_node,
+ NULL);
+ g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
+ }
+ gtk_tree_view_clamp_column_visible (tree_view, tree_view->priv->focus_column);
}
static void
}
static void
-gtk_tree_view_real_select_cursor_row (GtkTreeView *tree_view)
+gtk_tree_view_real_select_all (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->selection->type != GTK_SELECTION_MULTIPLE)
+ return;
+ gtk_tree_selection_select_all (tree_view->priv->selection);
+}
+
+static void
+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;
+
if (tree_view->priv->cursor)
cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
_gtk_tree_view_find_node (tree_view, cursor_path,
&cursor_tree, &cursor_node);
+
if (cursor_tree == NULL)
{
gtk_tree_path_free (cursor_path);
return;
}
-
+
+ gtk_get_current_event_state (&state);
+
+ if (start_editing && tree_view->priv->focus_column)
+ {
+ if (gtk_tree_view_start_editing (tree_view, cursor_path))
+ {
+ gtk_tree_path_free (cursor_path);
+ return;
+ }
+ }
_gtk_tree_selection_internal_select_node (tree_view->priv->selection,
cursor_node,
cursor_tree,
cursor_path,
- 0);
+ state);
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_view_queue_draw_node (tree_view, cursor_tree, cursor_node, NULL);
+ gtk_tree_view_row_activated (tree_view, cursor_path, tree_view->priv->focus_column);
+
gtk_tree_path_free (cursor_path);
}
gboolean open_all)
{
GtkTreePath *cursor_path = NULL;
+ GtkRBTree *tree;
+ GtkRBNode *node;
cursor_path = NULL;
if (tree_view->priv->cursor)
if (cursor_path == NULL)
return;
+ if (_gtk_tree_view_find_node (tree_view, cursor_path, &tree, &node))
+ return;
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
+
if (expand)
- gtk_tree_view_expand_row (tree_view, cursor_path, open_all);
+ gtk_tree_view_real_expand_row (tree_view, cursor_path, tree, node, open_all, TRUE);
else
- gtk_tree_view_collapse_row (tree_view, cursor_path);
+ gtk_tree_view_real_collapse_row (tree_view, cursor_path, tree, node, TRUE);
- 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);
}
gtk_tree_path_free (cursor_path);
}
-void
-_gtk_tree_view_update_size (GtkTreeView *tree_view)
+static void
+gtk_tree_view_real_start_interactive_search (GtkTreeView *tree_view)
{
- gint width, height;
- GList *list;
- GtkTreeViewColumn *column;
- gint vertical_separator;
- gint i;
-
- gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
+ GtkWidget *window;
+ GtkWidget *entry;
+ GtkWidget *search_dialog;
- if (tree_view->priv->model == NULL)
- {
- tree_view->priv->width = 0;
- tree_view->priv->height = 0;
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- return;
- }
+ if (tree_view->priv->enable_search == FALSE ||
+ tree_view->priv->search_column < 0)
+ return;
- width = 0;
- for (list = tree_view->priv->columns, i = 0; list; list = list->next, i++)
- {
- column = list->data;
- if (!column->visible)
- continue;
- width += TREE_VIEW_COLUMN_WIDTH (column);
- }
+ search_dialog = gtk_object_get_data (GTK_OBJECT (tree_view),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
+ if (search_dialog)
+ return;
- if (tree_view->priv->tree == NULL)
- height = 0;
- else
- height = tree_view->priv->tree->root->offset + vertical_separator;
+ /* 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);
+ gtk_signal_connect
+ (GTK_OBJECT (window), "delete_event",
+ GTK_SIGNAL_FUNC (gtk_tree_view_search_delete_event),
+ tree_view);
+ gtk_signal_connect
+ (GTK_OBJECT (window), "key_press_event",
+ GTK_SIGNAL_FUNC (gtk_tree_view_search_key_press_event),
+ tree_view);
+ gtk_signal_connect
+ (GTK_OBJECT (window), "button_press_event",
+ GTK_SIGNAL_FUNC (gtk_tree_view_search_button_press_event),
+ tree_view);
- if (tree_view->priv->width != width)
- {
- tree_view->priv->width = width;
- tree_view->priv->hadjustment->upper = width;
- gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->hadjustment), "changed");
- }
+ /* add entry */
+ entry = gtk_entry_new ();
+ gtk_widget_show (entry);
+ gtk_signal_connect
+ (GTK_OBJECT (entry), "changed",
+ GTK_SIGNAL_FUNC (gtk_tree_view_search_init),
+ tree_view);
+ gtk_container_add (GTK_CONTAINER (window), entry);
- if (tree_view->priv->height != height)
- {
- tree_view->priv->height = height;
- tree_view->priv->vadjustment->upper = tree_view->priv->height;
- gtk_signal_emit_by_name (GTK_OBJECT (tree_view->priv->vadjustment), "changed");
- }
+ /* done, show it */
+ tree_view->priv->search_dialog_position_func (tree_view, window);
+ gtk_widget_show_all (window);
+ gtk_widget_grab_focus (entry);
- if (GTK_WIDGET_REALIZED (tree_view))
- {
- gdk_window_resize (tree_view->priv->bin_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), height + TREE_VIEW_HEADER_HEIGHT (tree_view));
- gdk_window_resize (tree_view->priv->header_window, MAX (width, GTK_WIDGET (tree_view)->allocation.width), tree_view->priv->header_height);
+ /* position window */
- _gtk_tree_view_update_col_width (tree_view);
- }
+ gtk_object_set_data_full (GTK_OBJECT (window), "gtk-tree-view-text",
+ g_strdup (gtk_entry_get_text (GTK_ENTRY (entry))),
+ (GDestroyNotify) g_free);
+ gtk_object_set_data (GTK_OBJECT (tree_view),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY, window);
- gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ /* search first matching iter */
+ gtk_tree_view_search_init (entry, tree_view);
}
/* this function returns the new width of the column being resized given
{
if (GTK_WIDGET_REALIZED (tree_view))
{
+ gint dy;
gdk_window_move (tree_view->priv->bin_window,
- tree_view->priv->hadjustment->value,
- - tree_view->priv->vadjustment->value);
+ 0);
gdk_window_move (tree_view->priv->header_window,
- tree_view->priv->hadjustment->value,
0);
+ dy = tree_view->priv->dy - (int) tree_view->priv->vadjustment->value;
+ gdk_window_scroll (tree_view->priv->bin_window, 0, dy);
+ tree_view->priv->dy = (int) tree_view->priv->vadjustment->value;
gdk_window_process_updates (tree_view->priv->bin_window, TRUE);
gdk_window_process_updates (tree_view->priv->header_window, TRUE);
* gtk_tree_view_get_model:
* @tree_view: a #GtkTreeView
*
- * Returns the model the the #GtkTreeView is based on. Returns NULL if the
+ * Returns the model the the #GtkTreeView is based on. Returns %NULL if the
* model is unset.
*
- * Return value: A #GtkTreeModel, or NULL if none is currently being used.
+ * Return value: A #GtkTreeModel, or %NULL if none is currently being used.
**/
GtkTreeModel *
gtk_tree_view_get_model (GtkTreeView *tree_view)
* @model: The model.
*
* Sets the model for a #GtkTreeView. If the @tree_view already has a model
- * set, it will remove it before setting the new model. If @model is NULL, then
+ * set, it will remove it before setting the new model. If @model is %NULL, then
* it will unset the old model.
**/
void
if (tree_view->priv->model)
{
+ gtk_tree_view_unref_and_check_selection_tree (tree_view, tree_view->priv->tree);
+
g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
- gtk_tree_view_range_changed, tree_view);
+ gtk_tree_view_row_changed, tree_view);
g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
- gtk_tree_view_inserted, tree_view);
+ gtk_tree_view_row_inserted, tree_view);
g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
- gtk_tree_view_has_child_toggled, tree_view);
+ gtk_tree_view_row_has_child_toggled, tree_view);
g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
- gtk_tree_view_deleted, tree_view);
+ gtk_tree_view_row_deleted, tree_view);
g_signal_handlers_disconnect_by_func (G_OBJECT (tree_view->priv->model),
- gtk_tree_view_reordered, tree_view);
+ gtk_tree_view_rows_reordered, tree_view);
if (tree_view->priv->tree)
{
_gtk_rbtree_free (tree_view->priv->tree);
tree_view->priv->tree = NULL;
}
- if (tree_view->priv->drag_dest_row)
- {
- gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
- tree_view->priv->drag_dest_row = NULL;
- }
+ gtk_tree_row_reference_free (tree_view->priv->drag_dest_row);
+ tree_view->priv->drag_dest_row = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->cursor);
+ tree_view->priv->cursor = NULL;
+ gtk_tree_row_reference_free (tree_view->priv->anchor);
+ tree_view->priv->anchor = NULL;
+
g_object_unref (tree_view->priv->model);
tree_view->priv->search_column = -1;
}
}
g_object_ref (tree_view->priv->model);
g_signal_connect (tree_view->priv->model,
- "range_changed",
- G_CALLBACK (gtk_tree_view_range_changed),
+ "row_changed",
+ G_CALLBACK (gtk_tree_view_row_changed),
tree_view);
g_signal_connect (tree_view->priv->model,
- "inserted",
- G_CALLBACK (gtk_tree_view_inserted),
+ "row_inserted",
+ G_CALLBACK (gtk_tree_view_row_inserted),
tree_view);
g_signal_connect (tree_view->priv->model,
- "has_child_toggled",
- G_CALLBACK (gtk_tree_view_has_child_toggled),
+ "row_has_child_toggled",
+ G_CALLBACK (gtk_tree_view_row_has_child_toggled),
tree_view);
g_signal_connect (tree_view->priv->model,
- "deleted",
- G_CALLBACK (gtk_tree_view_deleted),
+ "row_deleted",
+ G_CALLBACK (gtk_tree_view_row_deleted),
tree_view);
g_signal_connect (tree_view->priv->model,
- "reordered",
- G_CALLBACK (gtk_tree_view_reordered),
+ "rows_reordered",
+ G_CALLBACK (gtk_tree_view_rows_reordered),
tree_view);
path = gtk_tree_path_new_root ();
if (gtk_tree_model_get_iter (tree_view->priv->model, &iter, path))
{
tree_view->priv->tree = _gtk_rbtree_new ();
- gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE, GTK_WIDGET_REALIZED (tree_view));
+ gtk_tree_view_build_tree (tree_view, tree_view->priv->tree, &iter, 1, FALSE);
}
gtk_tree_path_free (path);
/* FIXME: do I need to do this? gtk_tree_view_create_buttons (tree_view); */
}
- if (GTK_WIDGET_REALIZED (tree_view))
- _gtk_tree_view_update_size (tree_view);
g_object_notify (G_OBJECT (tree_view), "model");
+
+ if (GTK_WIDGET_REALIZED (tree_view))
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
/**
*
* Gets the #GtkAdjustment currently being used for the horizontal aspect.
*
- * Return value: A #GtkAdjustment object, or NULL if none is currently being
+ * Return value: A #GtkAdjustment object, or %NULL if none is currently being
* used.
**/
GtkAdjustment *
/**
* gtk_tree_view_set_hadjustment:
* @tree_view: A #GtkTreeView
- * @adjustment: The #GtkAdjustment to set, or NULL
+ * @adjustment: The #GtkAdjustment to set, or %NULL
*
* Sets the #GtkAdjustment for the current horizontal aspect.
**/
*
* Gets the #GtkAdjustment currently being used for the vertical aspect.
*
- * Return value: A #GtkAdjustment object, or NULL if none is currently being
+ * Return value: A #GtkAdjustment object, or %NULL if none is currently being
* used.
**/
GtkAdjustment *
/**
* gtk_tree_view_set_vadjustment:
* @tree_view: A #GtkTreeView
- * @adjustment: The #GtkAdjustment to set, or NULL
+ * @adjustment: The #GtkAdjustment to set, or %NULL
*
* Sets the #GtkAdjustment for the current vertical aspect.
**/
* gtk_tree_view_get_headers_visible:
* @tree_view: A #GtkTreeView.
*
- * Returns TRUE if the headers on the @tree_view are visible.
+ * Returns %TRUE if the headers on the @tree_view are visible.
*
* Return value: Whether the headers are visible or not.
**/
/**
* gtk_tree_view_set_headers_visible:
* @tree_view: A #GtkTreeView.
- * @headers_visible: TRUE if the headers are visible
+ * @headers_visible: %TRUE if the headers are visible
*
* Sets the the visibility state of the headers.
**/
column = list->data;
if (column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
continue;
- column->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (column);
dirty = TRUE;
}
/**
* gtk_tree_view_set_headers_clickable:
* @tree_view: A #GtkTreeView.
- * @setting: TRUE if the columns are clickable.
+ * @setting: %TRUE if the columns are clickable.
*
* Allow the column title buttons to be clicked.
**/
* This function tells GTK+ that the user interface for your
* application requires users to read across tree rows and associate
* cells with one another. By default, GTK+ will then render the tree
- * with alternating row colors. <emphasis>DO NOT</emphasis> use it
+ * with alternating row colors. Do <emphasis>not</emphasis> use it
* just because you prefer the appearance of the ruled tree; that's a
* question for the theme. Some themes will draw tree rows in
* alternating colors even when rules are turned off, and users who
tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
if (tmp_column->visible)
- tmp_column->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (tmp_column);
}
if (tree_view->priv->n_columns == 0 &&
{
column = GTK_TREE_VIEW_COLUMN (list->data);
if (column->visible)
- column->dirty = TRUE;
+ gtk_tree_view_column_cell_set_dirty (column);
}
gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
* @position: The position to insert the new column in.
* @title: The title to set the header to.
* @cell: The #GtkCellRenderer.
- * @Varargs: A NULL terminated list of attributes.
+ * @Varargs: A %NULL-terminated list of attributes.
*
* 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
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (column, title);
- gtk_tree_view_column_set_cell_renderer (column, cell);
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
va_start (args, cell);
* Convenience function that inserts a new column into the #GtkTreeView
* 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_set_cell_renderer().
+ * gtk_tree_view_column_set_cell_data_func(), gtk_tree_view_column_pack_start().
*
* Return value: number of columns in the tree view post-insert
**/
column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (column, title);
- gtk_tree_view_column_set_cell_renderer (column, cell);
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
gtk_tree_view_column_set_cell_data_func (column, cell, func, data, dnotify);
gtk_tree_view_insert_column (tree_view, column, position);
*
* Gets the #GtkTreeViewColumn at the given position in the #tree_view.
*
- * Return value: The #GtkTreeViewColumn, or NULL if the position is outside the
+ * Return value: The #GtkTreeViewColumn, or %NULL if the position is outside the
* range of columns.
**/
GtkTreeViewColumn *
* gtk_tree_view_move_column_after:
* @tree_view: A #GtkTreeView
* @column: The #GtkTreeViewColumn to be moved.
- * @base_column: The #GtkTreeViewColumn to be moved relative to.
+ * @base_column: The #GtkTreeViewColumn to be moved relative to, or %NULL.
*
- * Moves @column to be after to @base_column. If @base_column is NULL, then
+ * Moves @column to be after to @base_column. If @base_column is %NULL, then
* @column is placed in the first position.
**/
void
if (GTK_WIDGET_REALIZED (tree_view))
{
- //gtk_widget_queue_resize (GTK_WIDGET (tree_view));
- _gtk_tree_view_update_size (tree_view);
- gtk_tree_view_size_allocate_buttons (GTK_WIDGET (tree_view));
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
+ gtk_tree_view_size_allocate_columns (GTK_WIDGET (tree_view));
}
g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
/**
* gtk_tree_view_set_expander_column:
* @tree_view: A #GtkTreeView
- * @column: NULL, or the column to draw the expander arrow at.
- *
+ * @column: %NULL, or the column to draw the expander arrow at.
+ *
* Sets the column to draw the expander arrow at. It must be in @tree_view. If
- * @column is %NULL, then the expander arrow is fixed at the first column.
+ * @column is %NULL, then the expander arrow is always at the first visible
+ * column.
**/
void
gtk_tree_view_set_expander_column (GtkTreeView *tree_view,
GtkTreeViewColumn *
gtk_tree_view_get_expander_column (GtkTreeView *tree_view)
{
+ GList *list;
+
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
- return tree_view->priv->expander_column;
+ for (list = tree_view->priv->columns; list; list = list->data)
+ if (gtk_tree_view_is_expander_column (tree_view, GTK_TREE_VIEW_COLUMN (list->data)))
+ return (GtkTreeViewColumn *) list->data;
+ return NULL;
}
/**
* gtk_tree_view_set_column_drag_function:
* @tree_view: A #GtkTreeView.
- * @func: A function to determine which columns are reorderable, or NULL.
- * @user_data: User data to be passed to @func, or NULL
- * @destroy: Destroy notifier for @user_data, or NULL
+ * @func: A function to determine which columns are reorderable, or %NULL.
+ * @user_data: User data to be passed to @func, or %NULL
+ * @destroy: Destroy notifier for @user_data, or %NULL
*
* Sets a user function for determining where a column may be dropped when
* dragged. This function is called on every column pair in turn at the
* arguments passed to @func are: the @tree_view, the #GtkTreeViewColumn being
* dragged, the two #GtkTreeViewColumn s determining the drop spot, and
* @user_data. If either of the #GtkTreeViewColumn arguments for the drop spot
- * are NULL, then they indicate an edge. If @func is set to be NULL, then
+ * are %NULL, then they indicate an edge. If @func is set to be %NULL, then
* @tree_view reverts to the default behavior of allowing all columns to be
* dropped everywhere.
**/
* Scrolls the tree view such that the top-left corner of the visible
* area is @tree_x, @tree_y, where @tree_x and @tree_y are specified
* in tree window coordinates. The @tree_view must be realized before
- * this function is called. If it isn't, you probably want ot be
- * using gtk_tree_view_scroll_to_cell.
+ * this function is called. If it isn't, you probably want to be
+ * using gtk_tree_view_scroll_to_cell().
**/
void
gtk_tree_view_scroll_to_point (GtkTreeView *tree_view,
hadj = tree_view->priv->hadjustment;
vadj = tree_view->priv->vadjustment;
- gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper));
- gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper));
+ gtk_adjustment_set_value (hadj, CLAMP (tree_x, hadj->lower, hadj->upper - hadj->page_size));
+ gtk_adjustment_set_value (vadj, CLAMP (tree_y, vadj->lower, vadj->upper - vadj->page_size));
}
/**
* gtk_tree_view_scroll_to_cell
* @tree_view: A #GtkTreeView.
- * @path: The path of the row to move to.
- * @column: The #GtkTreeViewColumn to move horizontally to.
+ * @path: The path of the row to move to, or %NULL.
+ * @column: The #GtkTreeViewColumn to move horizontally to, or %NULL.
+ * @use_align: whether to use alignment arguments, or %FALSE.
* @row_align: The vertical alignment of the row specified by @path.
* @col_align: The horizontal alignment of the column specified by @column.
*
- * Moves the alignments of @tree_view to the position specified by
- * @column and @path. If @column is NULL, then no horizontal
- * scrolling occurs. Likewise, if @path is NULL no vertical scrolling
- * occurs. @row_align determines where the row is placed, and
- * @col_align determines where @column is placed. Both are expected
- * to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0 means
- * right/bottom alignment, 0.5 means center.
+ * Moves the alignments of @tree_view to the position specified by @column and
+ * @path. If @column is %NULL, then no horizontal scrolling occurs. Likewise,
+ * if @path is %NULL no vertical scrolling occurs. @row_align determines where
+ * the row is placed, and @col_align determines where @column is placed. Both
+ * are expected to be between 0.0 and 1.0. 0.0 means left/top alignment, 1.0
+ * means right/bottom alignment, 0.5 means center. 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.
**/
void
gtk_tree_view_scroll_to_cell (GtkTreeView *tree_view,
GtkTreePath *path,
GtkTreeViewColumn *column,
+ gboolean use_align,
gfloat row_align,
gfloat col_align)
{
GdkRectangle cell_rect;
GdkRectangle vis_rect;
gint dest_x, dest_y;
+ gfloat within_margin = 0;
/* FIXME work on unmapped/unrealized trees? maybe implement when
* we do incremental reflow for trees
tree_view->priv->scroll_to_path = gtk_tree_path_copy (path);
if (column)
tree_view->priv->scroll_to_column = column;
+ tree_view->priv->scroll_to_use_align = use_align;
tree_view->priv->scroll_to_row_align = row_align;
tree_view->priv->scroll_to_col_align = col_align;
dest_x = vis_rect.x;
dest_y = vis_rect.y;
- if (path)
+ if (column)
{
- dest_x = cell_rect.x +
- cell_rect.width * row_align -
- vis_rect.width * row_align;
+ if (use_align)
+ {
+ dest_x = cell_rect.x + cell_rect.width * row_align - vis_rect.width * row_align;
+ }
+ else
+ {
+ if (cell_rect.x < vis_rect.x)
+ dest_x = cell_rect.x - vis_rect.width * within_margin;
+ else if (cell_rect.x + cell_rect.width > vis_rect.x + vis_rect.width)
+ dest_x = cell_rect.x + cell_rect.width - vis_rect.width * (1 - within_margin);
+ }
}
- if (column)
+ if (path)
{
- dest_y = cell_rect.y +
- cell_rect.height * col_align -
- vis_rect.height * col_align;
+ if (use_align)
+ {
+ dest_y = cell_rect.y + cell_rect.height * col_align - vis_rect.height * col_align;
+ }
+ else
+ {
+ if (cell_rect.y < vis_rect.y)
+ dest_y = cell_rect.y - vis_rect.height * within_margin;
+ else if (cell_rect.y + cell_rect.height > vis_rect.y + vis_rect.height)
+ dest_y = cell_rect.y + cell_rect.height - vis_rect.height * (1 - within_margin);
+ }
}
gtk_tree_view_scroll_to_point (tree_view, dest_x, dest_y);
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- /* FIXME: Actually activate the path internally, not just emit the signal */
- /* g_warning ("FIXME: Actually activate the path internally, not just emit the signal\n"); */
g_signal_emit (G_OBJECT(tree_view), tree_view_signals[ROW_ACTIVATED], 0, path, column);
}
node->children,
&child,
gtk_tree_path_get_depth (path) + 1,
- TRUE,
- GTK_WIDGET_REALIZED (tree_view));
+ TRUE);
gtk_tree_path_free (path);
}
}
G_PRE_ORDER,
gtk_tree_view_expand_all_helper,
tree_view);
-
- _gtk_tree_view_update_size (tree_view);
-}
-
-static void
-gtk_tree_view_collapse_all_helper (GtkRBTree *tree,
- GtkRBNode *node,
- gpointer data)
-{
- if (node->children)
- {
- GtkTreePath *path;
- GtkTreeIter iter;
-
- path = _gtk_tree_view_find_path (GTK_TREE_VIEW (data),
- node->children,
- node->children->root);
- gtk_tree_model_get_iter (GTK_TREE_VIEW (data)->priv->model,
- &iter,
- path);
- gtk_tree_view_discover_dirty (GTK_TREE_VIEW (data),
- node->children,
- &iter,
- gtk_tree_path_get_depth (path));
-
- /* Ensure we don't have a dangling pointer to a dead node */
- ensure_unprelighted (GTK_TREE_VIEW (data));
-
- _gtk_rbtree_remove (node->children);
- gtk_tree_path_free (path);
- }
}
/* Timeout to animate the expander during expands and collapses */
gboolean redraw;
GDK_THREADS_ENTER ();
-
+
redraw = FALSE;
expanding = TRUE;
node = tree_view->priv->expanded_collapsed_node;
tree = tree_view->priv->expanded_collapsed_tree;
-
+
if (node->children == NULL)
expanding = FALSE;
GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
redraw = TRUE;
-
+
}
else if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SEMI_EXPANDED))
{
void
gtk_tree_view_collapse_all (GtkTreeView *tree_view)
{
+ GtkRBTree *tree;
+ GtkRBNode *node;
+ GtkTreePath *path;
+ guint *indices;
+
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (tree_view->priv->tree != NULL);
- _gtk_rbtree_traverse (tree_view->priv->tree,
- tree_view->priv->tree->root,
- G_PRE_ORDER,
- gtk_tree_view_collapse_all_helper,
- tree_view);
+ path = gtk_tree_path_new ();
+ gtk_tree_path_append_index (path, 0);
+ indices = gtk_tree_path_get_indices (path);
- if (GTK_WIDGET_MAPPED (tree_view))
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
+ tree = tree_view->priv->tree;
+ node = tree->root;
+ while (node && node->left != tree->nil)
+ node = node->left;
+
+ while (node)
+ {
+ if (node->children)
+ gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
+ indices[0]++;
+ node = _gtk_rbtree_next (tree, node);
+ }
+
+ gtk_tree_path_free (path);
}
/* FIXME the bool return values for expand_row and collapse_row are
GtkTreePath *path,
GtkRBTree *tree,
GtkRBNode *node,
- gboolean open_all)
+ gboolean open_all,
+ gboolean animate)
{
GtkTreeIter iter;
GtkTreeIter temp;
gboolean expand;
+
if (node->children)
return TRUE;
+ if (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_PARENT))
+ return FALSE;
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
if (! gtk_tree_model_iter_has_child (tree_view->priv->model, &iter))
node->children,
&temp,
gtk_tree_path_get_depth (path) + 1,
- open_all,
- GTK_WIDGET_REALIZED (tree_view));
+ open_all);
if (tree_view->priv->expand_collapse_timeout)
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
-
+ {
+ gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ tree_view->priv->expand_collapse_timeout = 0;
+ }
+
if (tree_view->priv->expanded_collapsed_node != NULL)
{
GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
- }
- tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
- tree_view->priv->expanded_collapsed_node = node;
- tree_view->priv->expanded_collapsed_tree = tree;
-
- GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
+ tree_view->priv->expanded_collapsed_node = NULL;
+ }
- if (GTK_WIDGET_MAPPED (tree_view))
+ if (animate)
{
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- _gtk_tree_view_update_size (tree_view);
+ tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expanded_collapsed_node = node;
+ tree_view->priv->expanded_collapsed_tree = tree;
+
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_COLLAPSED);
}
- g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
+ if (GTK_WIDGET_MAPPED (tree_view))
+ install_presize_handler (tree_view);
+ g_signal_emit (G_OBJECT (tree_view), tree_view_signals[ROW_EXPANDED], 0, &iter, path);
return TRUE;
}
* @path: path to a row
* @open_all: whether to recursively expand, or just expand immediate children
*
- * Opens the row so its children are visible
+ * Opens the row so its children are visible.
*
* Return value: %TRUE if the row existed and had children
**/
return FALSE;
if (tree != NULL)
- return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all);
+ return gtk_tree_view_real_expand_row (tree_view, path, tree, node, open_all, FALSE);
else
return FALSE;
}
gtk_tree_view_real_collapse_row (GtkTreeView *tree_view,
GtkTreePath *path,
GtkRBTree *tree,
- GtkRBNode *node)
+ GtkRBNode *node,
+ gboolean animate)
{
GtkTreeIter iter;
GtkTreeIter children;
gboolean collapse;
gint x, y;
+ GList *list;
+
+ if (node->children == NULL)
+ return FALSE;
gtk_tree_model_get_iter (tree_view->priv->model, &iter, path);
/* if the prelighted node is a child of us, we want to unprelight it. We have
* a chance to prelight the correct node below */
-
+
if (tree_view->priv->prelight_tree)
{
GtkRBTree *parent_tree;
TREE_VIEW_INTERNAL_ASSERT (gtk_tree_model_iter_children (tree_view->priv->model, &children, &iter), FALSE);
- gtk_tree_view_discover_dirty (tree_view,
- node->children,
- &children,
- gtk_tree_path_get_depth (path));
+ for (list = tree_view->priv->columns; list; list = list->next)
+ {
+ GtkTreeViewColumn *column = list->data;
+
+ if (column->visible == FALSE)
+ continue;
+ if (gtk_tree_view_column_get_sizing (column) == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
+ gtk_tree_view_column_cell_set_dirty (column);
+ }
if (tree_view->priv->destroy_count_func)
{
_gtk_rbtree_remove (node->children);
if (tree_view->priv->expand_collapse_timeout)
- gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
-
+ {
+ gtk_timeout_remove (tree_view->priv->expand_collapse_timeout);
+ tree_view->priv->expand_collapse_timeout = 0;
+ }
+
if (tree_view->priv->expanded_collapsed_node != NULL)
{
GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_EXPANDED);
GTK_RBNODE_UNSET_FLAG (tree_view->priv->expanded_collapsed_node, GTK_RBNODE_IS_SEMI_COLLAPSED);
+
+ tree_view->priv->expanded_collapsed_node = NULL;
}
- tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
- tree_view->priv->expanded_collapsed_node = node;
- tree_view->priv->expanded_collapsed_tree = tree;
+ if (animate)
+ {
+ tree_view->priv->expand_collapse_timeout = gtk_timeout_add (50, expand_collapse_timeout, tree_view);
+ tree_view->priv->expanded_collapsed_node = node;
+ tree_view->priv->expanded_collapsed_tree = tree;
- GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_IS_SEMI_EXPANDED);
+ }
if (GTK_WIDGET_MAPPED (tree_view))
{
- gtk_widget_queue_draw (GTK_WIDGET (tree_view));
- _gtk_tree_view_update_size (tree_view);
+ gtk_widget_queue_resize (GTK_WIDGET (tree_view));
}
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
* @tree_view: a #GtkTreeView
* @path: path to a row in the @tree_view
*
- * Collapses a row (hides its child rows, if they exist.)
+ * Collapses a row (hides its child rows, if they exist).
*
* Return value: %TRUE if the row was collapsed.
**/
if (tree == NULL || node->children == NULL)
return FALSE;
- return gtk_tree_view_real_collapse_row (tree_view, path, tree, node);
+ return gtk_tree_view_real_collapse_row (tree_view, path, tree, node, FALSE);
}
static void
* gtk_tree_view_row_expanded:
* @tree_view: A #GtkTreeView.
* @path: A #GtkTreePath to test expansion state.
- *
- * Returns TRUE if the node pointed to by @path is expanded in @tree_view.
- *
- * Return value: TRUE if #path is expanded.
+ *
+ * Returns %TRUE if the node pointed to by @path is expanded in @tree_view.
+ *
+ * Return value: %TRUE if #path is expanded.
**/
gboolean
gtk_tree_view_row_expanded (GtkTreeView *tree_view,
/**
* gtk_tree_view_set_reorderable:
* @tree_view: A #GtkTreeView.
- * @reorderable: TRUE, if the tree can be reordered.
+ * @reorderable: %TRUE, if the tree can be reordered.
*
* This function is a convenience function to allow you to reorder models that
* support the #GtkDragSourceIface and the #GtkDragDestIface. Both
- * #GtkTreeStore and #GtkListStore support these. If @reorderable is TRUE, then
+ * #GtkTreeStore and #GtkListStore support these. If @reorderable is %TRUE, then
* the user can reorder the model by dragging and dropping columns. The
- * developer will can listen to these changes by connecting to the model's
+ * developer can listen to these changes by connecting to the model's
* signals.
*
* This function does not give you any degree of control over the order -- any
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
+ reorderable = reorderable != FALSE;
+
+ if (tree_view->priv->reorderable == reorderable)
return;
- gtk_tree_view_set_rows_drag_source (tree_view,
- GDK_BUTTON1_MASK,
- row_targets,
- G_N_ELEMENTS (row_targets),
- GDK_ACTION_MOVE,
- NULL, NULL);
- gtk_tree_view_set_rows_drag_dest (tree_view,
- row_targets,
- G_N_ELEMENTS (row_targets),
- GDK_ACTION_MOVE,
- NULL, NULL);
+ tree_view->priv->reorderable = reorderable;
+
+ if (reorderable)
+ {
+ gtk_tree_view_enable_model_drag_source (tree_view,
+ GDK_BUTTON1_MASK,
+ row_targets,
+ G_N_ELEMENTS (row_targets),
+ GDK_ACTION_MOVE);
+ gtk_tree_view_enable_model_drag_dest (tree_view,
+ row_targets,
+ G_N_ELEMENTS (row_targets),
+ GDK_ACTION_MOVE);
+ }
+ else
+ {
+ gtk_tree_view_unset_rows_drag_source (tree_view);
+ gtk_tree_view_unset_rows_drag_dest (tree_view);
+ }
g_object_notify (G_OBJECT (tree_view), "reorderable");
}
{
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
+ GdkModifierType state = 0;
if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
{
gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL);
gtk_tree_path_free (cursor_path);
}
+
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,
path);
_gtk_tree_view_find_node (tree_view, path, &tree, &node);
- if (tree == NULL)
- return;
+ 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);
+ gtk_tree_view_clamp_node_visible (tree_view, tree, node);
+ gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
+ }
+
+ g_signal_emit (G_OBJECT (tree_view), tree_view_signals[CURSOR_CHANGED], 0);
+}
+
+/**
+ * gtk_tree_view_get_cursor:
+ * @tree_view: A #GtkTreeView
+ * @path: A pointer to be filled with the current cursor path, or %NULL
+ * @focus_column: A pointer to be filled with the current focus column, or %NULL
+ *
+ * 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.
+ **/
+void
+gtk_tree_view_get_cursor (GtkTreeView *tree_view,
+ GtkTreePath **path,
+ GtkTreeViewColumn **focus_column)
+{
+ g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+ if (path)
+ {
+ if (gtk_tree_row_reference_valid (tree_view->priv->cursor))
+ *path = gtk_tree_row_reference_get_path (tree_view->priv->cursor);
+ else
+ *path = NULL;
+ }
- if (clear_and_select && !tree_view->priv->in_free_motion)
- _gtk_tree_selection_internal_select_node (tree_view->priv->selection,
- node, tree, path,
- tree_view->priv->in_extended_selection?GDK_SHIFT_MASK:0);
- gtk_tree_view_clamp_node_visible (tree_view, tree, node);
- gtk_tree_view_queue_draw_node (tree_view, tree, node, NULL);
+ if (focus_column)
+ {
+ *focus_column = tree_view->priv->focus_column;
+ }
}
/**
* gtk_tree_view_set_cursor:
* @tree_view: A #GtkTreeView
* @path: A #GtkTreePath
+ * @focus_column: A #GtkTreeViewColumn, or %NULL
+ * @start_editing: %TRUE if the specified cell should start being edited.
*
* 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
- * you want to give the user keyboard focus in the tree_view, you should use
- * this function to set the correct path, and gtk_widget_grab_focus (GTK_WIDGET
- * (tree_view)) to actually give focus to the @tree_view.
+ * @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. Keyboard focus is given to
+ * the widget after this is called. Please note that editing can only happen
+ * when the widget is realized.
**/
void
-gtk_tree_view_set_cursor (GtkTreeView *tree_view,
- GtkTreePath *path)
+gtk_tree_view_set_cursor (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *focus_column,
+ gboolean start_editing)
{
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (path != NULL);
+ if (focus_column)
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (focus_column));
gtk_tree_view_real_set_cursor (tree_view, path, TRUE);
+
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+ if (focus_column && focus_column->visible)
+ {
+ GList *list;
+ gboolean column_in_tree = FALSE;
+
+ for (list = tree_view->priv->columns; list; list = list->next)
+ if (list->data == focus_column)
+ {
+ column_in_tree = TRUE;
+ break;
+ }
+ g_return_if_fail (column_in_tree);
+ tree_view->priv->focus_column = focus_column;
+ if (start_editing)
+ gtk_tree_view_start_editing (tree_view, path);
+ }
}
+/**
+ * gtk_tree_view_get_bin_window:
+ * @tree_view: A #GtkTreeView
+ *
+ * Returns the window that @tree_view renders to. This is used primarily to
+ * compare to <literal>event->window</literal> to confirm that the event on
+ * @tree_view is on the right window.
+ *
+ * Return value: A #GdkWindow, or %NULL when @tree_view hasn't been realized yet
+ **/
+GdkWindow *
+gtk_tree_view_get_bin_window (GtkTreeView *tree_view)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), NULL);
+
+ return tree_view->priv->bin_window;
+}
+
/**
* gtk_tree_view_get_path_at_pos:
* @tree_view: A #GtkTreeView.
- * @window: The #GdkWindow to check against.
* @x: The x position to be identified.
* @y: The y position to be identified.
* @path: A pointer to a #GtkTreePath pointer to be filled in, or %NULL
* @cell_x: A pointer where the X coordinate relative to the cell can be placed, or %NULL
* @cell_y: A pointer where the Y coordinate relative to the cell can be placed, or %NULL
*
- * Finds the path at the point (@x, @y) relative to @window. If @window is
- * NULL, then the point is found relative to the widget coordinates. This
- * function is expected to be called after an event, with event->window being
- * passed in as @window. It is primarily for things like popup menus. If @path
- * is non-NULL, then it will be filled with the #GtkTreePath at that point.
- * This path should be freed with #gtk_tree_path_free. If @column is non-NULL,
- * then it will be filled with the column at that point. @cell_x and @cell_y
- * return the coordinates relative to the cell background (i.e. the
- * background_area passed to gtk_cell_renderer_render()). This function only
- * works if @tree_view is realized.
+ * Finds the path at the point (@x, @y), relative to widget coordinates. That
+ * is, @x and @y are relative to an events coordinates. It is primarily for
+ * things like popup menus. If @path is non-%NULL, then it will be filled with
+ * the #GtkTreePath at that point. This path should be freed with
+ * gtk_tree_path_free(). If @column is non-%NULL, then it will be filled with
+ * the column at that point. @cell_x and @cell_y return the coordinates relative
+ * to the cell background (i.e. the @background_area passed to
+ * gtk_cell_renderer_render()). This function is only meaningful if @tree_view
+ * is realized.
*
- * Return value: TRUE if a row exists at that coordinate.
+ * Return value: %TRUE if a row exists at that coordinate.
**/
gboolean
gtk_tree_view_get_path_at_pos (GtkTreeView *tree_view,
- GdkWindow *window,
gint x,
gint y,
GtkTreePath **path,
gint y_offset;
g_return_val_if_fail (tree_view != NULL, FALSE);
- g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
- if (window)
- g_return_val_if_fail (window == tree_view->priv->bin_window, FALSE);
-
if (path)
*path = NULL;
if (column)
*column = NULL;
+ if (tree_view->priv->tree == NULL)
+ return FALSE;
+
if (x > tree_view->priv->hadjustment->upper)
return FALSE;
}
}
- if (window)
- {
- y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y),
- &tree, &node);
- }
- else
- {
- if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
- return FALSE;
+ if (y < TREE_VIEW_HEADER_HEIGHT (tree_view))
+ return FALSE;
- y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
- TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
- &tree, &node);
- }
+ y_offset = _gtk_rbtree_find_offset (tree_view->priv->tree,
+ TREE_WINDOW_Y_TO_RBTREE_Y (tree_view, y + tree_view->priv->vadjustment->value),
+ &tree, &node);
if (tree == NULL)
return FALSE;
*
* Fills the bounding rectangle in tree window coordinates for the cell at the
* row specified by @path and the column specified by @column. If @path is
- * %NULL, the y and height fields of the rectangle will be filled with 0. If
- * @column is %NULL, the x and width fields will be filled with 0. The sum of
- * all cell rects does not cover the entire tree; there are extra pixels in
- * between rows, for example. The returned rectangle is equivalent to the
- * @cell_area passed to gtk_cell_renderer_render(). This function is only valid
- * if #tree_view is realized.
+ * %NULL, or points to a path not currently displayed, the @y and @height fields
+ * of the rectangle will be filled with 0. If @column is %NULL, the @x and @width
+ * fields will be filled with 0. The sum of all cell rects does not cover the
+ * entire tree; there are extra pixels in between rows, for example. The
+ * returned rectangle is equivalent to the @cell_area passed to
+ * gtk_cell_renderer_render(). This function is only valid if #tree_view is
+ * realized.
**/
void
gtk_tree_view_get_cell_area (GtkTreeView *tree_view,
GtkRBTree *tree = NULL;
GtkRBNode *node = NULL;
gint vertical_separator;
+ gint horizontal_separator;
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
g_return_if_fail (column == NULL || GTK_IS_TREE_VIEW_COLUMN (column));
g_return_if_fail (rect != NULL);
- g_return_if_fail (column->tree_view == tree_view);
+ g_return_if_fail (!column || column->tree_view == (GtkWidget *) tree_view);
g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
- gtk_widget_style_get (GTK_WIDGET (tree_view), "vertical_separator", &vertical_separator, NULL);
+ gtk_widget_style_get (GTK_WIDGET (tree_view),
+ "vertical_separator", &vertical_separator,
+ "horizontal_separator", &horizontal_separator,
+ NULL);
rect->x = 0;
rect->y = 0;
rect->width = 0;
rect->height = 0;
- if (path)
+ if (column)
{
- /* Get vertical coords */
-
- _gtk_tree_view_find_node (tree_view, path, &tree, &node);
-
- if (tree == NULL)
- {
- g_warning (G_STRLOC": no row corresponding to path");
- return;
- }
+ rect->x = column->button->allocation.x + horizontal_separator/2;
+ rect->width = column->button->allocation.width - horizontal_separator;
+ }
- /* Remember that the rbtree stores node height including the vertical
- * separator, see comment at top of file.
- */
- rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
+ if (path)
+ {
+ /* Get vertical coords */
+ if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
+ tree != NULL)
+ return;
+ rect->y = CELL_FIRST_PIXEL (tree_view, tree, node, vertical_separator);
rect->height = CELL_HEIGHT (node, vertical_separator);
- }
- if (column)
- {
- rect->x = column->button->allocation.x;
- rect->width = column->button->allocation.width;
+ if (gtk_tree_view_is_expander_column (tree_view, column) &&
+ TREE_VIEW_DRAW_EXPANDERS (tree_view))
+ {
+ gint depth = gtk_tree_path_get_depth (path) - 1;
+ rect->x += depth * tree_view->priv->tab_offset;
+ rect->width -= depth * tree_view->priv->tab_offset;
+ rect->width = MAX (rect->width, 0);
+ }
}
}
* @column: a #GtkTreeViewColumn for the column, or %NULL to get only vertical coordiantes
* @rect: rectangle to fill with cell background rect
*
- * Fills the bounding rectangle in tree window coordinates for the
- * cell at the row specified by @path and the column specified by
- * @column. If @path is %NULL, the y and height fields of the
- * rectangle will be filled with 0. If @column is %NULL, the x and
- * width fields will be filled with 0. The returned rectangle is
- * equivalent to the @background_area passed to
- * gtk_cell_renderer_render(). These background areas tile to cover
- * the entire tree window (except for the area used for header
- * buttons). Contrast with the cell_area, returned by
- * gtk_tree_view_get_cell_area(), which returns only the cell itself,
- * excluding surrounding borders and the tree expander area.
+ * Fills the bounding rectangle in tree window coordinates for the cell at the
+ * row specified by @path and the column specified by @column. If @path is
+ * %NULL, or points to a node not found in the tree, the @y and @height fields of
+ * the rectangle will be filled with 0. If @column is %NULL, the @x and @width
+ * fields will be filled with 0. The returned rectangle is equivalent to the
+ * @background_area passed to gtk_cell_renderer_render(). These background
+ * areas tile to cover the entire tree window (except for the area used for
+ * header buttons). Contrast with the @cell_area, returned by
+ * gtk_tree_view_get_cell_area(), which returns only the cell itself, excluding
+ * surrounding borders and the tree expander area.
*
**/
void
{
/* Get vertical coords */
- _gtk_tree_view_find_node (tree_view, path, &tree, &node);
-
- if (tree == NULL)
- {
- g_warning (G_STRLOC": no row corresponding to path");
- return;
- }
+ if (_gtk_tree_view_find_node (tree_view, path, &tree, &node) &&
+ tree != NULL)
+ return;
rect->y = BACKGROUND_FIRST_PIXEL (tree_view, tree, node);
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
if (tx)
- {
- *tx = wx + tree_view->priv->hadjustment->value;
- }
-
+ *tx = wx + tree_view->priv->hadjustment->value;
if (ty)
- {
- *ty = wy + tree_view->priv->vadjustment->value;
- }
+ *ty = wy + tree_view->priv->vadjustment->value;
}
/**
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
if (wx)
- {
- *wx = tx - tree_view->priv->hadjustment->value;
- }
-
+ *wx = tx - tree_view->priv->hadjustment->value;
if (wy)
+ *wy = ty - tree_view->priv->vadjustment->value;
+}
+
+static void
+unset_reorderable (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->reorderable)
{
- *wy = ty - tree_view->priv->vadjustment->value;
+ tree_view->priv->reorderable = FALSE;
+ g_object_notify (G_OBJECT (tree_view), "reorderable");
}
}
-
void
-gtk_tree_view_set_rows_drag_source (GtkTreeView *tree_view,
- GdkModifierType start_button_mask,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions,
- GtkTreeViewDraggableFunc row_draggable_func,
- gpointer user_data)
+gtk_tree_view_enable_model_drag_source (GtkTreeView *tree_view,
+ GdkModifierType start_button_mask,
+ const GtkTargetEntry *targets,
+ gint n_targets,
+ GdkDragAction actions)
{
TreeViewDragInfo *di;
di->source_target_list = gtk_target_list_new (targets, n_targets);
di->source_actions = actions;
- if (row_draggable_func)
- {
- di->row_draggable_closure = g_cclosure_new ((GCallback) row_draggable_func,
- user_data, NULL);
- g_closure_ref (di->row_draggable_closure);
- g_closure_sink (di->row_draggable_closure);
- }
-
di->source_set = TRUE;
+
+ unset_reorderable (tree_view);
}
void
-gtk_tree_view_set_rows_drag_dest (GtkTreeView *tree_view,
- const GtkTargetEntry *targets,
- gint n_targets,
- GdkDragAction actions,
- GtkTreeViewDroppableFunc location_droppable_func,
- gpointer user_data)
+gtk_tree_view_enable_model_drag_dest (GtkTreeView *tree_view,
+ const GtkTargetEntry *targets,
+ gint n_targets,
+ GdkDragAction actions)
{
TreeViewDragInfo *di;
if (targets)
di->dest_target_list = gtk_target_list_new (targets, n_targets);
- if (location_droppable_func)
- {
- di->location_droppable_closure = g_cclosure_new ((GCallback) location_droppable_func,
- user_data, NULL);
- g_closure_ref (di->location_droppable_closure);
- g_closure_sink (di->location_droppable_closure);
- }
-
di->dest_set = TRUE;
+
+ unset_reorderable (tree_view);
}
void
if (!di->dest_set && !di->source_set)
remove_info (tree_view);
}
+
+ unset_reorderable (tree_view);
}
void
if (!di->dest_set && !di->source_set)
remove_info (tree_view);
}
+
+ unset_reorderable (tree_view);
}
void
*/
if (!gtk_tree_view_get_path_at_pos (tree_view,
- tree_view->priv->bin_window,
x, y,
&tmp_path,
&column,
* @tree_view: a #GtkTreeView
* @path: a #GtkTreePath in @tree_view
*
- * Creates a GdkPixmap representation of the row at @path. This image is used
+ * Creates a #GdkPixmap representation of the row at @path. This image is used
* for a drag icon.
*
- * Return value: a newly allocatdd pixmap of the drag icon.
+ * Return value: a newly-allocated pixmap of the drag icon.
**/
GdkPixmap *
gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view,
gint cell_offset;
GList *list;
GdkRectangle background_area;
+ GdkRectangle expose_area;
GtkWidget *widget;
gint depth;
/* start drawing inside the black outline */
background_area.height + 2,
-1);
+ expose_area.x = 0;
+ expose_area.y = 0;
+ expose_area.width = bin_window_width + 2;
+ expose_area.height = background_area.height + 2;
+
gdk_draw_rectangle (drawable,
widget->style->base_gc [GTK_WIDGET_STATE (widget)],
TRUE,
node->children?TRUE:FALSE);
background_area.x = cell_offset;
- background_area.width = column->displayed_width;
+ background_area.width = column->width;
cell_area = background_area;
drawable,
&background_area,
&cell_area,
- NULL,
+ &expose_area,
0);
- cell_offset += column->displayed_width;
+ cell_offset += column->width;
}
return drawable;
/**
* gtk_tree_view_set_destroy_count_func:
* @tree_view: A #GtkTreeView
- * @func: Function to be called when a view row is destroyed, or NULL
- * @data: User data to be passed to @func, or NULL
- * @destroy: Destroy notifier for @data, or NULL
- *
+ * @func: Function to be called when a view row is destroyed, or %NULL
+ * @data: User data to be passed to @func, or %NULL
+ * @destroy: Destroy notifier for @data, or %NULL
+ *
* This function should almost never be used. It is meant for private use by
* ATK for determining the number of visible children that are removed when the
* user collapses a row, or a row is deleted.
/*
- * Interactive search
+ * Interactive search
*/
/**
gtk_tree_view_get_search_column (GtkTreeView *tree_view)
{
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), 0);
-
+
return (tree_view->priv->search_column);
}
return;
tree_view->priv->search_column = column;
-
+
}
/**
/**
* gtk_tree_view_set_search_equal_func:
* @tree_view: A #GtkTreeView
- * @compare_func: the compare function to use during the search
+ * @search_equal_func: the compare function to use during the search
+ * @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 to use to search the TreeView.
- */
+ * Sets the compare function for the interactive search capabilities.
+ **/
void
gtk_tree_view_set_search_equal_func (GtkTreeView *tree_view,
GtkTreeViewSearchEqualFunc search_equal_func,
GtkTreeView *tree_view)
{
/* remove data from tree_view */
- gtk_object_remove_data (GTK_OBJECT (tree_view), "search-dialog");
-
+ gtk_object_remove_data (GTK_OBJECT (tree_view),
+ GTK_TREE_VIEW_SEARCH_DIALOG_KEY);
+
gtk_widget_destroy (search_dialog);
}
tree_y + tree_height);
}
-static void
-gtk_tree_view_interactive_search (GtkTreeView *tree_view,
- GdkEventKey *event)
-{
- GtkWidget *window;
- GtkWidget *entry;
-
- g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- switch (event->keyval)
- {
- case GDK_Shift_L:
- case GDK_Shift_R:
- case GDK_Control_L:
- case GDK_Control_R:
- case GDK_Caps_Lock:
- case GDK_Shift_Lock:
- case GDK_Meta_L:
- case GDK_Meta_R:
- case GDK_Alt_L:
- case GDK_Alt_R:
- case GDK_Super_L:
- case GDK_Super_R:
- case GDK_Hyper_L:
- case GDK_Hyper_R:
- case GDK_Mode_switch:
- return;
- default:
- break;
- }
-
- if (tree_view->priv->enable_search == FALSE ||
- tree_view->priv->search_column < 0)
- 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);
- gtk_signal_connect
- (GTK_OBJECT (window), "delete_event",
- GTK_SIGNAL_FUNC (gtk_tree_view_search_delete_event),
- tree_view);
- gtk_signal_connect
- (GTK_OBJECT (window), "key_press_event",
- GTK_SIGNAL_FUNC (gtk_tree_view_search_key_press_event),
- tree_view);
- gtk_signal_connect
- (GTK_OBJECT (window), "button_press_event",
- GTK_SIGNAL_FUNC (gtk_tree_view_search_button_press_event),
- tree_view);
-
- /* add entry */
- entry = gtk_entry_new ();
- gtk_widget_show (entry);
- gtk_signal_connect
- (GTK_OBJECT (entry), "changed",
- GTK_SIGNAL_FUNC (gtk_tree_view_search_init),
- tree_view);
- gtk_container_add (GTK_CONTAINER (window), entry);
-
- /* done, show it */
- tree_view->priv->search_dialog_position_func (tree_view, window);
- gtk_widget_show_all (window);
- gtk_widget_grab_focus (entry);
-
- gtk_widget_event (entry, (GdkEvent *) event);
-
- /* position window */
-
- gtk_object_set_data (GTK_OBJECT (window), "text",
- gtk_entry_get_text (GTK_ENTRY (entry)));
- gtk_object_set_data (GTK_OBJECT (tree_view), "search-dialog", window);
-
- /* search first matching iter */
- gtk_tree_view_search_init (entry, tree_view);
-}
-
static gboolean
gtk_tree_view_search_delete_event (GtkWidget *widget,
GdkEventAny *event,
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
gtk_tree_view_search_dialog_destroy (widget, tree_view);
-
+
return TRUE;
}
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
gtk_tree_view_search_dialog_destroy (widget, tree_view);
-
+
return TRUE;
}
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
g_return_val_if_fail (GTK_IS_TREE_VIEW (tree_view), FALSE);
-
+
/* close window */
- if (event->keyval == GDK_Escape || event->keyval == GDK_Return
- || event->keyval == GDK_Tab)
+ if (event->keyval == GDK_Escape ||
+ event->keyval == GDK_Return ||
+ event->keyval == GDK_Tab)
{
gtk_tree_view_search_dialog_destroy (widget, tree_view);
return TRUE;
/* select previous matching iter */
if (event->keyval == GDK_Up)
{
- gtk_tree_view_search_move (widget,
- tree_view,
- TRUE);
+ gtk_tree_view_search_move (widget, tree_view, TRUE);
return TRUE;
}
/* select next matching iter */
if (event->keyval == GDK_Down)
{
- gtk_tree_view_search_move (widget,
- tree_view,
- FALSE);
+ gtk_tree_view_search_move (widget, tree_view, FALSE);
return TRUE;
}
+
return FALSE;
}
GtkTreeModel *model;
GtkTreeSelection *selection;
- text = gtk_object_get_data (GTK_OBJECT (window), "text");
- selected_iter = gtk_object_get_data (GTK_OBJECT (window), "selected-iter");
+ text = gtk_object_get_data (GTK_OBJECT (window), "gtk-tree-view-text");
+ selected_iter = gtk_object_get_data (GTK_OBJECT (window), "gtk-tree-view-selected-iter");
g_return_if_fail (text != NULL);
return;
len = strlen (text);
-
+
if (len < 1)
return;
model = gtk_tree_view_get_model (tree_view);
selection = gtk_tree_view_get_selection (tree_view);
-
+
/* search */
gtk_tree_selection_unselect_all (selection);
gtk_tree_model_get_iter_root (model, &iter);
-
+
ret = gtk_tree_view_search_iter (model, selection, &iter, text,
&count, up?((*selected_iter) - 1):((*selected_iter + 1)));
-
+
if (ret)
- /* found */
- *selected_iter += up?(-1):(1);
+ {
+ /* found */
+ *selected_iter += up?(-1):(1);
+ }
else
{
/* return to old iter */
gtk_tree_view_search_iter (model, selection,
&iter, text,
&count, *selected_iter);
-
}
}
static gboolean
gtk_tree_view_search_equal_func (GtkTreeModel *model,
gint column,
- gchar *key,
- GtkTreeIter *iter)
+ const gchar *key,
+ GtkTreeIter *iter,
+ gpointer search_data)
{
gboolean retval = TRUE;
gchar *normalized_string;
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);
if (!strncmp (case_normalized_key, case_normalized_string, key_len))
retval = FALSE;
-
+
g_value_unset (&value);
g_free (normalized_key);
g_free (normalized_string);
gtk_tree_view_search_iter (GtkTreeModel *model,
GtkTreeSelection *selection,
GtkTreeIter *iter,
- gchar *text,
+ const gchar *text,
gint *count,
gint n)
{
+ GtkRBTree *tree = NULL;
+ GtkRBNode *node = NULL;
+ GtkTreePath *path;
+
GtkTreeView *tree_view = gtk_tree_selection_get_tree_view (selection);
GtkTreeViewColumn *column =
gtk_tree_view_get_column (tree_view, tree_view->priv->search_column);
-
- if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter))
- {
- (*count)++;
-
- if (*count == n)
- {
- GtkTreePath *path;
-
- gtk_tree_selection_select_iter (selection, iter);
-
- path = gtk_tree_model_get_path (model, iter);
- gtk_tree_view_scroll_to_cell (tree_view, path, column, 0.5, 0.5);
- gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
- gtk_tree_path_free (path);
-
- return TRUE;
- }
- }
-
- if (gtk_tree_model_iter_has_child (model, iter))
- {
- gboolean ret;
- GtkTreeIter child;
-
- gtk_tree_model_iter_children (model, &child, iter);
- ret = gtk_tree_view_search_iter (model, selection,
- &child, text,
- count, n);
-
- if (ret)
- return TRUE; /* iter found and selected */
- }
-
- while (gtk_tree_model_iter_next (model, iter))
+
+ path = gtk_tree_model_get_path (model, iter);
+ _gtk_tree_view_find_node (tree_view, path, &tree, &node);
+
+ do
{
- if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter))
+ if (! tree_view->priv->search_equal_func (model, tree_view->priv->search_column, text, iter, tree_view->priv->search_user_data))
{
(*count)++;
if (*count == n)
{
- GtkTreePath *path;
-
gtk_tree_selection_select_iter (selection, iter);
-
- path = gtk_tree_model_get_path (model, iter);
- gtk_tree_view_scroll_to_cell (tree_view, path, column, 0.5, 0.5);
+ gtk_tree_view_scroll_to_cell (tree_view, path, column,
+ TRUE, 0.5, 0.5);
gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
- gtk_tree_path_free (path);
-
+
+ if (path)
+ gtk_tree_path_free (path);
+
return TRUE;
}
}
-
- if (gtk_tree_model_iter_has_child (model, iter))
- {
- gboolean ret;
- GtkTreeIter child;
-
- gtk_tree_model_iter_children (model, &child, iter);
- ret = gtk_tree_view_search_iter (model, selection,
- &child, text,
- count, n);
-
- if (ret)
- return TRUE; /* iter found and selected */
- }
+
+ if (node->children)
+ {
+ gboolean has_child;
+ GtkTreeIter tmp;
+
+ tree = node->children;
+ node = tree->root;
+
+ while (node->left != tree->nil)
+ node = node->left;
+
+ tmp = *iter;
+ has_child = gtk_tree_model_iter_children (model, iter, &tmp);
+ gtk_tree_path_append_index (path, 0);
+
+ /* sanity check */
+ TREE_VIEW_INTERNAL_ASSERT (has_child, FALSE);
+ }
+ else
+ {
+ gboolean done = FALSE;
+
+ do
+ {
+ node = _gtk_rbtree_next (tree, node);
+
+ if (node)
+ {
+ gboolean has_next;
+
+ has_next = gtk_tree_model_iter_next (model, iter);
+
+ done = TRUE;
+ gtk_tree_path_next (path);
+
+ /* sanity check */
+ TREE_VIEW_INTERNAL_ASSERT (has_next, FALSE);
+ }
+ else
+ {
+ gboolean has_parent;
+ GtkTreeIter tmp_iter = *iter;
+
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+
+ if (!tree)
+ {
+ if (path)
+ gtk_tree_path_free (path);
+
+ /* we've run out of tree, done with this func */
+ return FALSE;
+ }
+
+ has_parent = gtk_tree_model_iter_parent (model,
+ iter,
+ &tmp_iter);
+ gtk_tree_path_up (path);
+
+ /* sanity check */
+ TREE_VIEW_INTERNAL_ASSERT (has_parent, FALSE);
+ }
+ }
+ while (!done);
+ }
}
+ while (1);
+
+ if (path)
+ gtk_tree_path_free (path);
return FALSE;
}
gint *selected_iter;
gint len;
gint count = 0;
- gchar *text;
+ const gchar *text;
GtkWidget *window;
GtkTreeIter iter;
GtkTreeModel *model;
GtkTreeSelection *selection;
-
+
g_return_if_fail (GTK_IS_ENTRY (entry));
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-
+
window = gtk_widget_get_parent (entry);
text = gtk_entry_get_text (GTK_ENTRY (entry));
len = strlen (text);
/* search */
gtk_tree_selection_unselect_all (selection);
- selected_iter = gtk_object_get_data (GTK_OBJECT (window), "selected-iter");
+ selected_iter = gtk_object_get_data (GTK_OBJECT (window), "gtk-tree-view-selected-iter");
if (selected_iter)
g_free (selected_iter);
- gtk_object_remove_data (GTK_OBJECT (window), "selected-iter");
+ gtk_object_remove_data (GTK_OBJECT (window), "gtk-tree-view-selected-iter");
if (len < 1)
return;
-
+
gtk_tree_model_get_iter_root (model, &iter);
-
+
ret = gtk_tree_view_search_iter (model, selection,
&iter, text,
&count, 1);
- if (ret)
+ if (ret)
{
selected_iter = g_malloc (sizeof (int));
*selected_iter = 1;
- gtk_object_set_data (GTK_OBJECT (window), "selected-iter",
+ gtk_object_set_data (GTK_OBJECT (window), "gtk-tree-view-selected-iter",
selected_iter);
}
}
+
+static void
+gtk_tree_view_remove_widget (GtkCellEditable *cell_editable,
+ GtkTreeView *tree_view)
+{
+ g_return_if_fail (tree_view->priv->edited_column != NULL);
+ _gtk_tree_view_column_stop_editing (tree_view->priv->edited_column);
+ tree_view->priv->edited_column = NULL;
+
+ gtk_container_remove (GTK_CONTAINER (tree_view),
+ GTK_WIDGET (cell_editable));
+ gtk_widget_grab_focus (GTK_WIDGET (tree_view));
+}
+
+static gboolean
+gtk_tree_view_start_editing (GtkTreeView *tree_view,
+ GtkTreePath *cursor_path)
+{
+ GtkTreeIter iter;
+ GdkRectangle background_area;
+ GdkRectangle cell_area;
+ GtkCellEditable *editable_widget = NULL;
+ gchar *path_string;
+ guint flags = 0; /* can be 0, as the flags are primarily for rendering */
+ gint retval = FALSE;
+ GtkRBTree *cursor_tree;
+ GtkRBNode *cursor_node;
+
+ g_assert (tree_view->priv->focus_column);
+
+ if (! GTK_WIDGET_REALIZED (tree_view))
+ return FALSE;
+
+ if (_gtk_tree_view_find_node (tree_view, cursor_path, &cursor_tree, &cursor_node) ||
+ cursor_node == NULL)
+ return FALSE;
+
+ path_string = gtk_tree_path_to_string (cursor_path);
+ gtk_tree_model_get_iter (tree_view->priv->model, &iter, cursor_path);
+ gtk_tree_view_column_cell_set_cell_data (tree_view->priv->focus_column,
+ tree_view->priv->model,
+ &iter,
+ GTK_RBNODE_FLAG_SET (cursor_node, GTK_RBNODE_IS_PARENT),
+ cursor_node->children?TRUE:FALSE);
+ gtk_tree_view_get_background_area (tree_view,
+ cursor_path,
+ tree_view->priv->focus_column,
+ &background_area);
+ gtk_tree_view_get_cell_area (tree_view,
+ cursor_path,
+ tree_view->priv->focus_column,
+ &cell_area);
+ if (_gtk_tree_view_column_cell_event (tree_view->priv->focus_column,
+ &editable_widget,
+ NULL,
+ path_string,
+ &background_area,
+ &cell_area,
+ flags))
+ {
+ retval = TRUE;
+ if (editable_widget != NULL)
+ {
+ gtk_tree_view_real_start_editing (tree_view,
+ tree_view->priv->focus_column,
+ cursor_path,
+ editable_widget,
+ &cell_area,
+ NULL,
+ flags);
+ }
+
+ }
+ g_free (path_string);
+ return retval;
+}
+
+static void
+gtk_tree_view_real_start_editing (GtkTreeView *tree_view,
+ GtkTreeViewColumn *column,
+ GtkTreePath *path,
+ GtkCellEditable *cell_editable,
+ GdkRectangle *cell_area,
+ GdkEvent *event,
+ guint flags)
+{
+ tree_view->priv->edited_column = column;
+ _gtk_tree_view_column_start_editing (column, GTK_CELL_EDITABLE (cell_editable));
+ gtk_tree_view_real_set_cursor (tree_view, path, FALSE);
+ GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS);
+ gtk_tree_view_put (tree_view,
+ GTK_WIDGET (cell_editable),
+ cell_area->x, cell_area->y, cell_area->width, cell_area->height);
+ gtk_cell_editable_start_editing (GTK_CELL_EDITABLE (cell_editable),
+ (GdkEvent *)event);
+ gtk_widget_grab_focus (GTK_WIDGET (cell_editable));
+ g_signal_connect (cell_editable, "remove_widget", G_CALLBACK (gtk_tree_view_remove_widget), tree_view);
+}
+
+static void
+gtk_tree_view_stop_editing (GtkTreeView *tree_view)
+{
+ if (tree_view->priv->edited_column == NULL)
+ return;
+
+ gtk_cell_editable_editing_done (tree_view->priv->edited_column->editable_widget);
+ gtk_cell_editable_remove_widget (tree_view->priv->edited_column->editable_widget);
+}