diff options
author | Kristian Rietveld <kris@imendio.com> | 2007-08-22 14:26:32 +0000 |
---|---|---|
committer | Kristian Rietveld <kristian@src.gnome.org> | 2007-08-22 14:26:32 +0000 |
commit | 31fc4289c7436542bdbc9c2fcb2c1127bfcf2089 (patch) | |
tree | a304e6c2bf215765a64fa04f400987cc508481a3 /gtk | |
parent | 0f9230d30aa6c19b480536444f8cb12c1c462a08 (diff) | |
download | gtk+-31fc4289c7436542bdbc9c2fcb2c1127bfcf2089.tar.gz |
Do not allow the cursor to go to a separator row. Fixes #441219, modified
2007-08-22 Kristian Rietveld <kris@imendio.com>
Do not allow the cursor to go to a separator row. Fixes #441219,
modified patch by Carlos Garnacho.
* gtk/gtktreeview.c (row_is_separator): new inline function
for calling the row-separator-func, made all of gtktreeview.c use
this function instead of calling the func themselves,
(gtk_tree_view_button_press): treat a click on a separator like
a click on empty space,
(gtk_tree_view_update_rubber_band_selection_rage): skip
non-selectable rows,
(search_first_focusable_path),
(gtk_tree_view_focus_to_cursor),
(gtk_tree_view_move_cursor_up_down),
(gtk_tree_view_move_cursor_page_up_down),
(gtk_tree_view_move_cursor_start_end): skip separators,
(gtk_tree_view_real_set_cursor): do not allow setting the cursor
on a separator.
svn path=/trunk/; revision=18672
Diffstat (limited to 'gtk')
-rw-r--r-- | gtk/gtktreeview.c | 242 |
1 files changed, 200 insertions, 42 deletions
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 3812a37e5b..8e21633cba 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -2433,6 +2433,30 @@ grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view) GTK_TREE_VIEW_UNSET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); } +static inline gboolean +row_is_separator (GtkTreeView *tree_view, + GtkTreeIter *iter, + GtkTreePath *path) +{ + gboolean is_separator = FALSE; + + if (tree_view->priv->row_separator_func) + { + GtkTreeIter tmpiter; + + if (iter) + tmpiter = *iter; + else + gtk_tree_model_get_iter (tree_view->priv->model, &tmpiter, path); + + is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, + &tmpiter, + tree_view->priv->row_separator_data); + } + + return is_separator; +} + static gboolean gtk_tree_view_button_press (GtkWidget *widget, GdkEventButton *event) @@ -2445,6 +2469,7 @@ gtk_tree_view_button_press (GtkWidget *widget, GdkRectangle cell_area; gint vertical_separator; gint horizontal_separator; + gboolean path_is_selectable; gboolean rtl; g_return_val_if_fail (GTK_IS_TREE_VIEW (widget), FALSE); @@ -2524,6 +2549,15 @@ gtk_tree_view_button_press (GtkWidget *widget, /* Get the path and the node */ path = _gtk_tree_view_find_path (tree_view, tree, node); + path_is_selectable = !row_is_separator (tree_view, NULL, path); + + if (!path_is_selectable) + { + gtk_tree_path_free (path); + grab_focus_and_unset_draw_keyfocus (tree_view); + return TRUE; + } + depth = gtk_tree_path_get_depth (path); background_area.y = y_offset + event->y; background_area.height = ROW_HEIGHT (tree_view, GTK_RBNODE_GET_HEIGHT (node)); @@ -3696,6 +3730,22 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view, do { + /* Small optimization by assuming insensitive nodes are never + * selected. + */ + if (!GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED)) + { + GtkTreePath *path; + gboolean selectable; + + path = _gtk_tree_view_find_path (tree_view, start_tree, start_node); + selectable = _gtk_tree_selection_row_is_selectable (tree_view->priv->selection, start_node, path); + gtk_tree_path_free (path); + + if (!selectable) + goto node_not_selectable; + } + if (select) { if (tree_view->priv->rubber_band_shift) @@ -3730,6 +3780,7 @@ gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view, _gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL); +node_not_selectable: if (start_node == end_node) break; @@ -4274,12 +4325,7 @@ gtk_tree_view_bin_expose (GtkWidget *widget, gboolean is_first = FALSE; gboolean is_last = FALSE; - if (tree_view->priv->row_separator_func) - { - is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, - &iter, - tree_view->priv->row_separator_data); - } + is_separator = row_is_separator (tree_view, &iter, NULL); max_height = ROW_HEIGHT (tree_view, BACKGROUND_HEIGHT (node)); @@ -5519,12 +5565,7 @@ validate_row (GtkTreeView *tree_view, ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) return FALSE; - if (tree_view->priv->row_separator_func) - { - is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, - iter, - tree_view->priv->row_separator_data); - } + is_separator = row_is_separator (tree_view, iter, NULL); gtk_widget_style_get (GTK_WIDGET (tree_view), "focus-padding", &focus_pad, @@ -7746,6 +7787,52 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, return (focus_child != NULL); } +/* This function returns in 'path' the first focusable path, if the given path + * is already focusable, it's the returned one. + */ +static gboolean +search_first_focusable_path (GtkTreeView *tree_view, + GtkTreePath **path, + gboolean search_forward, + GtkRBTree **new_tree, + GtkRBNode **new_node) +{ + GtkRBTree *tree = NULL; + GtkRBNode *node = NULL; + + if (!path || !*path) + return FALSE; + + _gtk_tree_view_find_node (tree_view, *path, &tree, &node); + + if (!tree || !node) + return FALSE; + + while (node && row_is_separator (tree_view, NULL, *path)) + { + if (search_forward) + _gtk_rbtree_next_full (tree, node, &tree, &node); + else + _gtk_rbtree_prev_full (tree, node, &tree, &node); + + if (*path) + gtk_tree_path_free (*path); + + if (node) + *path = _gtk_tree_view_find_path (tree_view, tree, node); + else + *path = NULL; + } + + if (new_tree) + *new_tree = tree; + + if (new_node) + *new_node = node; + + return (*path != NULL); +} + static gint gtk_tree_view_focus (GtkWidget *widget, GtkDirectionType direction) @@ -9496,21 +9583,22 @@ gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view) (! GTK_WIDGET_REALIZED (tree_view))) return; - GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); - cursor_path = NULL; if (tree_view->priv->cursor) cursor_path = gtk_tree_row_reference_get_path (tree_view->priv->cursor); if (cursor_path == NULL) { - /* Consult the selection before defaulting to the first element */ + /* Consult the selection before defaulting to the + * first focusable element + */ + GList *selected_rows; + GtkTreeModel *model; GtkTreeSelection *selection; - GtkTreeModel *model; - GList *selected_rows; selection = gtk_tree_view_get_selection (tree_view); selected_rows = gtk_tree_selection_get_selected_rows (selection, &model); + if (selected_rows) { cursor_path = gtk_tree_path_copy((const GtkTreePath *)(selected_rows->data)); @@ -9518,28 +9606,41 @@ gtk_tree_view_focus_to_cursor (GtkTreeView *tree_view) g_list_free (selected_rows); } else - cursor_path = gtk_tree_path_new_first (); + { + cursor_path = gtk_tree_path_new_first (); + search_first_focusable_path (tree_view, &cursor_path, + TRUE, NULL, NULL); + } gtk_tree_row_reference_free (tree_view->priv->cursor); tree_view->priv->cursor = NULL; - if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE) - gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE); - else - gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); + if (cursor_path) + { + if (tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE) + gtk_tree_view_real_set_cursor (tree_view, cursor_path, FALSE, FALSE); + else + gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); + } } - gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL); - gtk_tree_path_free (cursor_path); - if (tree_view->priv->focus_column == NULL) + if (cursor_path) { - GList *list; - for (list = tree_view->priv->columns; list; list = list->next) + GTK_TREE_VIEW_SET_FLAG (tree_view, GTK_TREE_VIEW_DRAW_KEYFOCUS); + + gtk_tree_view_queue_draw_path (tree_view, cursor_path, NULL); + gtk_tree_path_free (cursor_path); + + if (tree_view->priv->focus_column == NULL) { - if (GTK_TREE_VIEW_COLUMN (list->data)->visible) + GList *list; + for (list = tree_view->priv->columns; list; list = list->next) { - tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data); - break; + if (GTK_TREE_VIEW_COLUMN (list->data)->visible) + { + tree_view->priv->focus_column = GTK_TREE_VIEW_COLUMN (list->data); + break; + } } } } @@ -9594,6 +9695,20 @@ gtk_tree_view_move_cursor_up_down (GtkTreeView *tree_view, &new_cursor_tree, &new_cursor_node); } + if (new_cursor_node) + { + cursor_path = _gtk_tree_view_find_path (tree_view, + new_cursor_tree, new_cursor_node); + + search_first_focusable_path (tree_view, &cursor_path, + (count != -1), + &new_cursor_tree, + &new_cursor_node); + + if (cursor_path) + gtk_tree_path_free (cursor_path); + } + /* * If the list has only one item and multi-selection is set then select * the row (if not yet selected). @@ -9665,6 +9780,8 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, GtkRBNode *cursor_node = NULL; GtkTreePath *old_cursor_path = NULL; GtkTreePath *cursor_path = NULL; + GtkRBTree *start_cursor_tree = NULL; + GtkRBNode *start_cursor_node = NULL; gint y; gint window_y; gint vertical_separator; @@ -9712,7 +9829,33 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, y -= tree_view->priv->cursor_offset; cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); - g_return_if_fail (cursor_path != NULL); + + start_cursor_tree = cursor_tree; + start_cursor_node = cursor_node; + + if (! search_first_focusable_path (tree_view, &cursor_path, + (count != -1), + &cursor_tree, &cursor_node)) + { + /* It looks like we reached the end of the view without finding + * a focusable row. We will step backwards to find the last + * focusable row. + */ + cursor_tree = start_cursor_tree; + cursor_node = start_cursor_node; + cursor_path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); + + search_first_focusable_path (tree_view, &cursor_path, + (count == -1), + &cursor_tree, &cursor_node); + } + + if (!cursor_path) + goto cleanup; + + /* update y */ + y = _gtk_rbtree_node_find_offset (cursor_tree, cursor_node); + gtk_tree_view_real_set_cursor (tree_view, cursor_path, TRUE, FALSE); y -= window_y; @@ -9722,6 +9865,7 @@ gtk_tree_view_move_cursor_page_up_down (GtkTreeView *tree_view, if (!gtk_tree_path_compare (old_cursor_path, cursor_path)) gtk_widget_error_bell (GTK_WIDGET (tree_view)); +cleanup: gtk_tree_path_free (old_cursor_path); gtk_tree_path_free (cursor_path); } @@ -9848,6 +9992,11 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, { while (cursor_node && cursor_node->left != cursor_tree->nil) cursor_node = cursor_node->left; + + /* Now go forward to find the first focusable row. */ + path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); + search_first_focusable_path (tree_view, &path, + TRUE, &cursor_tree, &cursor_node); } else { @@ -9862,9 +10011,15 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, cursor_node = cursor_tree->root; } while (1); + + /* Now go backwards to find last focusable row. */ + path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); + search_first_focusable_path (tree_view, &path, + FALSE, &cursor_tree, &cursor_node); } - path = _gtk_tree_view_find_path (tree_view, cursor_tree, cursor_node); + if (!path) + goto cleanup; if (gtk_tree_path_compare (old_path, path)) { @@ -9875,6 +10030,7 @@ gtk_tree_view_move_cursor_start_end (GtkTreeView *tree_view, gtk_widget_error_bell (GTK_WIDGET (tree_view)); } +cleanup: gtk_tree_path_free (old_path); gtk_tree_path_free (path); } @@ -12352,11 +12508,18 @@ gtk_tree_view_real_set_cursor (GtkTreeView *tree_view, } gtk_tree_row_reference_free (tree_view->priv->cursor); + tree_view->priv->cursor = NULL; + + /* One cannot set the cursor on a separator. */ + if (!row_is_separator (tree_view, NULL, path)) + { + 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); + } - 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) { GtkRBTree *new_tree = NULL; @@ -13550,12 +13713,7 @@ gtk_tree_view_create_row_drag_icon (GtkTreeView *tree_view, path)) return NULL; - if (tree_view->priv->row_separator_func) - { - is_separator = (* tree_view->priv->row_separator_func) (tree_view->priv->model, - &iter, - tree_view->priv->row_separator_data); - } + is_separator = row_is_separator (tree_view, &iter, NULL); cell_offset = x; |