mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
Rubber banding for GtkTreeView, #80127. Uses same method as GtkIconView.
2006-06-02 Kristian Rietveld <kris@imendio.com> Rubber banding for GtkTreeView, #80127. Uses same method as GtkIconView. * gtk/gtktreeview.c (gtk_tree_view_class_init), (gtk_tree_view_init), (gtk_tree_view_get_property), (gtk_tree_view_set_property), (gtk_tree_view_set_rubber_banding), (gtk_tree_view_get_rubber_banding): add property, (gtk_tree_view_button_press): start rubber banding if enabled and press is on a non-selected node, (gtk_tree_view_button_release): stop rubber banding, (gtk_tree_view_motion_bin_window), (scrool_row_timeout): enable/update the rubber band, (gtk_tree_view_bin_expose): draw rubber band if active, (gtk_tree_view_stop_rubberband), (gtk_tree_view_update_rubber_band_selection_range), (gtk_tree_view_update_rubber_band_selection), (gtk_tree_view_update_rubber_band), (gtk_tree_view_paint_rubber_band): new functions. * gtk/gtktreeview.h: add new set/get function for rubber banding property. * gtk/gtktreeprivate.h: add a bunch of new private fields.
This commit is contained in:
parent
29018576b7
commit
f6c583f74e
26
ChangeLog
26
ChangeLog
@ -1,3 +1,29 @@
|
|||||||
|
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
||||||
|
|
||||||
|
Rubber banding for GtkTreeView, #80127. Uses same method as
|
||||||
|
GtkIconView.
|
||||||
|
|
||||||
|
* gtk/gtktreeview.c (gtk_tree_view_class_init),
|
||||||
|
(gtk_tree_view_init), (gtk_tree_view_get_property),
|
||||||
|
(gtk_tree_view_set_property), (gtk_tree_view_set_rubber_banding),
|
||||||
|
(gtk_tree_view_get_rubber_banding): add property,
|
||||||
|
(gtk_tree_view_button_press): start rubber banding if enabled and
|
||||||
|
press is on a non-selected node,
|
||||||
|
(gtk_tree_view_button_release): stop rubber banding,
|
||||||
|
(gtk_tree_view_motion_bin_window), (scrool_row_timeout): enable/update
|
||||||
|
the rubber band,
|
||||||
|
(gtk_tree_view_bin_expose): draw rubber band if active,
|
||||||
|
(gtk_tree_view_stop_rubberband),
|
||||||
|
(gtk_tree_view_update_rubber_band_selection_range),
|
||||||
|
(gtk_tree_view_update_rubber_band_selection),
|
||||||
|
(gtk_tree_view_update_rubber_band),
|
||||||
|
(gtk_tree_view_paint_rubber_band): new functions.
|
||||||
|
|
||||||
|
* gtk/gtktreeview.h: add new set/get function for rubber banding
|
||||||
|
property.
|
||||||
|
|
||||||
|
* gtk/gtktreeprivate.h: add a bunch of new private fields.
|
||||||
|
|
||||||
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
||||||
|
|
||||||
* gtk/gtktreeview.c (gtk_tree_view_leave_notify)P: revert fix of
|
* gtk/gtktreeview.c (gtk_tree_view_leave_notify)P: revert fix of
|
||||||
|
@ -1,3 +1,29 @@
|
|||||||
|
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
||||||
|
|
||||||
|
Rubber banding for GtkTreeView, #80127. Uses same method as
|
||||||
|
GtkIconView.
|
||||||
|
|
||||||
|
* gtk/gtktreeview.c (gtk_tree_view_class_init),
|
||||||
|
(gtk_tree_view_init), (gtk_tree_view_get_property),
|
||||||
|
(gtk_tree_view_set_property), (gtk_tree_view_set_rubber_banding),
|
||||||
|
(gtk_tree_view_get_rubber_banding): add property,
|
||||||
|
(gtk_tree_view_button_press): start rubber banding if enabled and
|
||||||
|
press is on a non-selected node,
|
||||||
|
(gtk_tree_view_button_release): stop rubber banding,
|
||||||
|
(gtk_tree_view_motion_bin_window), (scrool_row_timeout): enable/update
|
||||||
|
the rubber band,
|
||||||
|
(gtk_tree_view_bin_expose): draw rubber band if active,
|
||||||
|
(gtk_tree_view_stop_rubberband),
|
||||||
|
(gtk_tree_view_update_rubber_band_selection_range),
|
||||||
|
(gtk_tree_view_update_rubber_band_selection),
|
||||||
|
(gtk_tree_view_update_rubber_band),
|
||||||
|
(gtk_tree_view_paint_rubber_band): new functions.
|
||||||
|
|
||||||
|
* gtk/gtktreeview.h: add new set/get function for rubber banding
|
||||||
|
property.
|
||||||
|
|
||||||
|
* gtk/gtktreeprivate.h: add a bunch of new private fields.
|
||||||
|
|
||||||
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
2006-06-02 Kristian Rietveld <kris@imendio.com>
|
||||||
|
|
||||||
* gtk/gtktreeview.c (gtk_tree_view_leave_notify)P: revert fix of
|
* gtk/gtktreeview.c (gtk_tree_view_leave_notify)P: revert fix of
|
||||||
|
@ -58,6 +58,13 @@ enum
|
|||||||
DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
|
DRAG_COLUMN_WINDOW_STATE_ARROW_RIGHT = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RUBBER_BAND_OFF = 0,
|
||||||
|
RUBBER_BAND_MAYBE_START = 1,
|
||||||
|
RUBBER_BAND_ACTIVE = 2
|
||||||
|
};
|
||||||
|
|
||||||
#define GTK_TREE_VIEW_SET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END
|
#define GTK_TREE_VIEW_SET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags|=flag); }G_STMT_END
|
||||||
#define GTK_TREE_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END
|
#define GTK_TREE_VIEW_UNSET_FLAG(tree_view, flag) G_STMT_START{ (tree_view->priv->flags&=~(flag)); }G_STMT_END
|
||||||
#define GTK_TREE_VIEW_FLAG_SET(tree_view, flag) ((tree_view->priv->flags&flag)==flag)
|
#define GTK_TREE_VIEW_FLAG_SET(tree_view, flag) ((tree_view->priv->flags&flag)==flag)
|
||||||
@ -172,6 +179,18 @@ struct _GtkTreeViewPrivate
|
|||||||
gint press_start_x;
|
gint press_start_x;
|
||||||
gint press_start_y;
|
gint press_start_y;
|
||||||
|
|
||||||
|
gint rubber_band_status;
|
||||||
|
gint rubber_band_x;
|
||||||
|
gint rubber_band_y;
|
||||||
|
gint rubber_band_shift;
|
||||||
|
gint rubber_band_ctrl;
|
||||||
|
|
||||||
|
GtkRBNode *rubber_band_start_node;
|
||||||
|
GtkRBTree *rubber_band_start_tree;
|
||||||
|
|
||||||
|
GtkRBNode *rubber_band_end_node;
|
||||||
|
GtkRBTree *rubber_band_end_tree;
|
||||||
|
|
||||||
/* fixed height */
|
/* fixed height */
|
||||||
gint fixed_height;
|
gint fixed_height;
|
||||||
|
|
||||||
@ -210,6 +229,8 @@ struct _GtkTreeViewPrivate
|
|||||||
guint hover_expand : 1;
|
guint hover_expand : 1;
|
||||||
guint imcontext_changed : 1;
|
guint imcontext_changed : 1;
|
||||||
|
|
||||||
|
guint rubber_banding_enable : 1;
|
||||||
|
|
||||||
|
|
||||||
/* Auto expand/collapse timeout in hover mode */
|
/* Auto expand/collapse timeout in hover mode */
|
||||||
guint auto_expand_timeout;
|
guint auto_expand_timeout;
|
||||||
|
@ -135,7 +135,8 @@ enum {
|
|||||||
PROP_HOVER_SELECTION,
|
PROP_HOVER_SELECTION,
|
||||||
PROP_HOVER_EXPAND,
|
PROP_HOVER_EXPAND,
|
||||||
PROP_SHOW_EXPANDERS,
|
PROP_SHOW_EXPANDERS,
|
||||||
PROP_LEVEL_INDENTATION
|
PROP_LEVEL_INDENTATION,
|
||||||
|
PROP_RUBBER_BANDING
|
||||||
};
|
};
|
||||||
|
|
||||||
/* object signals */
|
/* object signals */
|
||||||
@ -379,6 +380,7 @@ static void column_sizing_notify (GObject
|
|||||||
gpointer data);
|
gpointer data);
|
||||||
static gboolean expand_collapse_timeout (gpointer data);
|
static gboolean expand_collapse_timeout (gpointer data);
|
||||||
static gboolean do_expand_collapse (GtkTreeView *tree_view);
|
static gboolean do_expand_collapse (GtkTreeView *tree_view);
|
||||||
|
static void gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view);
|
||||||
|
|
||||||
/* interactive search */
|
/* interactive search */
|
||||||
static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
|
static void gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view);
|
||||||
@ -455,6 +457,8 @@ static void gtk_tree_view_tree_window_to_tree_coords (GtkTreeView *tree_view,
|
|||||||
gint *tx,
|
gint *tx,
|
||||||
gint *ty);
|
gint *ty);
|
||||||
|
|
||||||
|
static gint scroll_row_timeout (gpointer data);
|
||||||
|
static void remove_scroll_timeout (GtkTreeView *tree_view);
|
||||||
|
|
||||||
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
|
static guint tree_view_signals [LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
@ -697,6 +701,14 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
|
|||||||
0,
|
0,
|
||||||
GTK_PARAM_READWRITE));
|
GTK_PARAM_READWRITE));
|
||||||
|
|
||||||
|
g_object_class_install_property (o_class,
|
||||||
|
PROP_RUBBER_BANDING,
|
||||||
|
g_param_spec_boolean ("rubber-banding",
|
||||||
|
P_("Rubber Banding"),
|
||||||
|
P_("Whether to enable selection of multiple items by dragging the mouse pointer"),
|
||||||
|
FALSE,
|
||||||
|
GTK_PARAM_READWRITE));
|
||||||
|
|
||||||
/* Style properties */
|
/* Style properties */
|
||||||
#define _TREE_VIEW_EXPANDER_SIZE 12
|
#define _TREE_VIEW_EXPANDER_SIZE 12
|
||||||
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
|
#define _TREE_VIEW_VERTICAL_SEPARATOR 2
|
||||||
@ -1247,6 +1259,8 @@ gtk_tree_view_init (GtkTreeView *tree_view)
|
|||||||
tree_view->priv->hover_expand = FALSE;
|
tree_view->priv->hover_expand = FALSE;
|
||||||
|
|
||||||
tree_view->priv->level_indentation = 0;
|
tree_view->priv->level_indentation = 0;
|
||||||
|
|
||||||
|
tree_view->priv->rubber_banding_enable = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1314,6 +1328,9 @@ gtk_tree_view_set_property (GObject *object,
|
|||||||
case PROP_LEVEL_INDENTATION:
|
case PROP_LEVEL_INDENTATION:
|
||||||
tree_view->priv->level_indentation = g_value_get_int (value);
|
tree_view->priv->level_indentation = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RUBBER_BANDING:
|
||||||
|
tree_view->priv->rubber_banding_enable = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1376,6 +1393,9 @@ gtk_tree_view_get_property (GObject *object,
|
|||||||
case PROP_LEVEL_INDENTATION:
|
case PROP_LEVEL_INDENTATION:
|
||||||
g_value_set_int (value, tree_view->priv->level_indentation);
|
g_value_set_int (value, tree_view->priv->level_indentation);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RUBBER_BANDING:
|
||||||
|
g_value_set_boolean (value, tree_view->priv->rubber_banding_enable);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@ -2310,6 +2330,7 @@ gtk_tree_view_button_press (GtkWidget *widget,
|
|||||||
gint column_handled_click = FALSE;
|
gint column_handled_click = FALSE;
|
||||||
gboolean row_double_click = FALSE;
|
gboolean row_double_click = FALSE;
|
||||||
gboolean rtl;
|
gboolean rtl;
|
||||||
|
gboolean node_selected;
|
||||||
|
|
||||||
/* Empty tree? */
|
/* Empty tree? */
|
||||||
if (tree_view->priv->tree == NULL)
|
if (tree_view->priv->tree == NULL)
|
||||||
@ -2478,6 +2499,7 @@ gtk_tree_view_button_press (GtkWidget *widget,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* select */
|
/* select */
|
||||||
|
node_selected = GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_IS_SELECTED);
|
||||||
pre_val = tree_view->priv->vadjustment->value;
|
pre_val = tree_view->priv->vadjustment->value;
|
||||||
|
|
||||||
/* we only handle selection modifications on the first button press
|
/* we only handle selection modifications on the first button press
|
||||||
@ -2530,6 +2552,21 @@ gtk_tree_view_button_press (GtkWidget *widget,
|
|||||||
tree_view->priv->pressed_button = event->button;
|
tree_view->priv->pressed_button = event->button;
|
||||||
tree_view->priv->press_start_x = event->x;
|
tree_view->priv->press_start_x = event->x;
|
||||||
tree_view->priv->press_start_y = event->y;
|
tree_view->priv->press_start_y = event->y;
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_banding_enable
|
||||||
|
&& !node_selected
|
||||||
|
&& tree_view->priv->selection->type == GTK_SELECTION_MULTIPLE)
|
||||||
|
{
|
||||||
|
tree_view->priv->press_start_y += tree_view->priv->dy;
|
||||||
|
tree_view->priv->rubber_band_x = event->x;
|
||||||
|
tree_view->priv->rubber_band_y = event->y + tree_view->priv->dy;
|
||||||
|
tree_view->priv->rubber_band_status = RUBBER_BAND_MAYBE_START;
|
||||||
|
|
||||||
|
if ((event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
|
||||||
|
tree_view->priv->rubber_band_ctrl = TRUE;
|
||||||
|
if ((event->state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
|
||||||
|
tree_view->priv->rubber_band_shift = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test if a double click happened on the same row. */
|
/* Test if a double click happened on the same row. */
|
||||||
@ -2745,6 +2782,9 @@ gtk_tree_view_button_release (GtkWidget *widget,
|
|||||||
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
|
if (GTK_TREE_VIEW_FLAG_SET (tree_view, GTK_TREE_VIEW_IN_COLUMN_DRAG))
|
||||||
return gtk_tree_view_button_release_drag_column (widget, event);
|
return gtk_tree_view_button_release_drag_column (widget, event);
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_band_status)
|
||||||
|
gtk_tree_view_stop_rubber_band (tree_view);
|
||||||
|
|
||||||
if (tree_view->priv->pressed_button == event->button)
|
if (tree_view->priv->pressed_button == event->button)
|
||||||
tree_view->priv->pressed_button = -1;
|
tree_view->priv->pressed_button = -1;
|
||||||
|
|
||||||
@ -3443,6 +3483,335 @@ gtk_tree_view_motion_drag_column (GtkWidget *widget,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_tree_view_stop_rubber_band (GtkTreeView *tree_view)
|
||||||
|
{
|
||||||
|
remove_scroll_timeout (tree_view);
|
||||||
|
gtk_grab_remove (GTK_WIDGET (tree_view));
|
||||||
|
|
||||||
|
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
|
||||||
|
{
|
||||||
|
GtkTreePath *tmp_path;
|
||||||
|
|
||||||
|
/* The anchor path should be set to the start path */
|
||||||
|
tmp_path = _gtk_tree_view_find_path (tree_view,
|
||||||
|
tree_view->priv->rubber_band_start_tree,
|
||||||
|
tree_view->priv->rubber_band_start_node);
|
||||||
|
|
||||||
|
if (tree_view->priv->anchor)
|
||||||
|
gtk_tree_row_reference_free (tree_view->priv->anchor);
|
||||||
|
|
||||||
|
tree_view->priv->anchor =
|
||||||
|
gtk_tree_row_reference_new_proxy (G_OBJECT (tree_view),
|
||||||
|
tree_view->priv->model,
|
||||||
|
tmp_path);
|
||||||
|
|
||||||
|
gtk_tree_path_free (tmp_path);
|
||||||
|
|
||||||
|
/* ... and the cursor to the end path */
|
||||||
|
tmp_path = _gtk_tree_view_find_path (tree_view,
|
||||||
|
tree_view->priv->rubber_band_end_tree,
|
||||||
|
tree_view->priv->rubber_band_end_node);
|
||||||
|
gtk_tree_view_real_set_cursor (GTK_TREE_VIEW (tree_view), tmp_path, FALSE, FALSE);
|
||||||
|
gtk_tree_path_free (tmp_path);
|
||||||
|
|
||||||
|
_gtk_tree_selection_emit_changed (tree_view->priv->selection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear status variables */
|
||||||
|
tree_view->priv->rubber_band_status = RUBBER_BAND_OFF;
|
||||||
|
tree_view->priv->rubber_band_shift = 0;
|
||||||
|
tree_view->priv->rubber_band_ctrl = 0;
|
||||||
|
|
||||||
|
tree_view->priv->rubber_band_start_node = NULL;
|
||||||
|
tree_view->priv->rubber_band_start_tree = NULL;
|
||||||
|
tree_view->priv->rubber_band_end_node = NULL;
|
||||||
|
tree_view->priv->rubber_band_end_tree = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (GtkTreeView *tree_view,
|
||||||
|
GtkRBTree *start_tree,
|
||||||
|
GtkRBNode *start_node,
|
||||||
|
GtkRBTree *end_tree,
|
||||||
|
GtkRBNode *end_node,
|
||||||
|
gboolean select,
|
||||||
|
gboolean skip_start,
|
||||||
|
gboolean skip_end)
|
||||||
|
{
|
||||||
|
if (start_node == end_node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We skip the first node and jump inside the loop */
|
||||||
|
if (skip_start)
|
||||||
|
goto skip_first;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (select)
|
||||||
|
{
|
||||||
|
if (tree_view->priv->rubber_band_shift)
|
||||||
|
GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
else if (tree_view->priv->rubber_band_ctrl)
|
||||||
|
{
|
||||||
|
/* Toggle the selection state */
|
||||||
|
if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
|
||||||
|
GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
else
|
||||||
|
GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Mirror the above */
|
||||||
|
if (tree_view->priv->rubber_band_shift)
|
||||||
|
GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
else if (tree_view->priv->rubber_band_ctrl)
|
||||||
|
{
|
||||||
|
/* Toggle the selection state */
|
||||||
|
if (GTK_RBNODE_FLAG_SET (start_node, GTK_RBNODE_IS_SELECTED))
|
||||||
|
GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
else
|
||||||
|
GTK_RBNODE_SET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
GTK_RBNODE_UNSET_FLAG (start_node, GTK_RBNODE_IS_SELECTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
_gtk_tree_view_queue_draw_node (tree_view, start_tree, start_node, NULL);
|
||||||
|
|
||||||
|
if (start_node == end_node)
|
||||||
|
break;
|
||||||
|
|
||||||
|
skip_first:
|
||||||
|
|
||||||
|
if (start_node->children)
|
||||||
|
{
|
||||||
|
start_tree = start_node->children;
|
||||||
|
start_node = start_tree->root;
|
||||||
|
while (start_node->left != start_tree->nil)
|
||||||
|
start_node = start_node->left;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_gtk_rbtree_next_full (start_tree, start_node, &start_tree, &start_node);
|
||||||
|
|
||||||
|
if (!start_tree)
|
||||||
|
/* Ran out of tree */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skip_end && start_node == end_node)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_tree_view_update_rubber_band_selection (GtkTreeView *tree_view)
|
||||||
|
{
|
||||||
|
GtkRBTree *start_tree, *end_tree;
|
||||||
|
GtkRBNode *start_node, *end_node;
|
||||||
|
|
||||||
|
_gtk_rbtree_find_offset (tree_view->priv->tree, MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &start_tree, &start_node);
|
||||||
|
_gtk_rbtree_find_offset (tree_view->priv->tree, MAX (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y), &end_tree, &end_node);
|
||||||
|
|
||||||
|
/* Handle the start area first */
|
||||||
|
if (!tree_view->priv->rubber_band_start_node)
|
||||||
|
{
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
start_tree,
|
||||||
|
start_node,
|
||||||
|
end_tree,
|
||||||
|
end_node,
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
else if (_gtk_rbtree_node_find_offset (start_tree, start_node) <
|
||||||
|
_gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
|
||||||
|
{
|
||||||
|
/* New node is above the old one; selection became bigger */
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
start_tree,
|
||||||
|
start_node,
|
||||||
|
tree_view->priv->rubber_band_start_tree,
|
||||||
|
tree_view->priv->rubber_band_start_node,
|
||||||
|
TRUE,
|
||||||
|
FALSE,
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
|
else if (_gtk_rbtree_node_find_offset (start_tree, start_node) >
|
||||||
|
_gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_start_tree, tree_view->priv->rubber_band_start_node))
|
||||||
|
{
|
||||||
|
/* New node is below the old one; selection became smaller */
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
tree_view->priv->rubber_band_start_tree,
|
||||||
|
tree_view->priv->rubber_band_start_node,
|
||||||
|
start_tree,
|
||||||
|
start_node,
|
||||||
|
FALSE,
|
||||||
|
FALSE,
|
||||||
|
TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_view->priv->rubber_band_start_tree = start_tree;
|
||||||
|
tree_view->priv->rubber_band_start_node = start_node;
|
||||||
|
|
||||||
|
/* Next, handle the end area */
|
||||||
|
if (!tree_view->priv->rubber_band_end_node)
|
||||||
|
{
|
||||||
|
/* In the event this happens, start_node was also NULL; this case is
|
||||||
|
* handled above.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else if (!end_node)
|
||||||
|
{
|
||||||
|
/* Find the last node in the tree */
|
||||||
|
_gtk_rbtree_find_offset (tree_view->priv->tree, tree_view->priv->height - 1,
|
||||||
|
&end_tree, &end_node);
|
||||||
|
|
||||||
|
/* Selection reached end of the tree */
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
tree_view->priv->rubber_band_end_tree,
|
||||||
|
tree_view->priv->rubber_band_end_node,
|
||||||
|
end_tree,
|
||||||
|
end_node,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
else if (_gtk_rbtree_node_find_offset (end_tree, end_node) >
|
||||||
|
_gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
|
||||||
|
{
|
||||||
|
/* New node is below the old one; selection became bigger */
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
tree_view->priv->rubber_band_end_tree,
|
||||||
|
tree_view->priv->rubber_band_end_node,
|
||||||
|
end_tree,
|
||||||
|
end_node,
|
||||||
|
TRUE,
|
||||||
|
TRUE,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
else if (_gtk_rbtree_node_find_offset (end_tree, end_node) <
|
||||||
|
_gtk_rbtree_node_find_offset (tree_view->priv->rubber_band_end_tree, tree_view->priv->rubber_band_end_node))
|
||||||
|
{
|
||||||
|
/* New node is above the old one; selection became smaller */
|
||||||
|
gtk_tree_view_update_rubber_band_selection_range (tree_view,
|
||||||
|
end_tree,
|
||||||
|
end_node,
|
||||||
|
tree_view->priv->rubber_band_end_tree,
|
||||||
|
tree_view->priv->rubber_band_end_node,
|
||||||
|
FALSE,
|
||||||
|
TRUE,
|
||||||
|
FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree_view->priv->rubber_band_end_tree = end_tree;
|
||||||
|
tree_view->priv->rubber_band_end_node = end_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_tree_view_update_rubber_band (GtkTreeView *tree_view)
|
||||||
|
{
|
||||||
|
gint x, y;
|
||||||
|
GdkRectangle old_area;
|
||||||
|
GdkRectangle new_area;
|
||||||
|
GdkRectangle common;
|
||||||
|
GdkRegion *invalid_region;
|
||||||
|
|
||||||
|
old_area.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
|
||||||
|
old_area.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
|
||||||
|
old_area.width = ABS (tree_view->priv->rubber_band_x - tree_view->priv->press_start_x) + 1;
|
||||||
|
old_area.height = ABS (tree_view->priv->rubber_band_y - tree_view->priv->press_start_y) + 1;
|
||||||
|
|
||||||
|
gdk_window_get_pointer (tree_view->priv->bin_window, &x, &y, NULL);
|
||||||
|
|
||||||
|
x = MAX (x, 0);
|
||||||
|
y = MAX (y, 0) + tree_view->priv->dy;
|
||||||
|
|
||||||
|
new_area.x = MIN (tree_view->priv->press_start_x, x);
|
||||||
|
new_area.y = MIN (tree_view->priv->press_start_y, y) - tree_view->priv->dy;
|
||||||
|
new_area.width = ABS (x - tree_view->priv->press_start_x) + 1;
|
||||||
|
new_area.height = ABS (y - tree_view->priv->press_start_y) + 1;
|
||||||
|
|
||||||
|
invalid_region = gdk_region_rectangle (&old_area);
|
||||||
|
gdk_region_union_with_rect (invalid_region, &new_area);
|
||||||
|
|
||||||
|
gdk_rectangle_intersect (&old_area, &new_area, &common);
|
||||||
|
if (common.width > 2 && common.height > 2)
|
||||||
|
{
|
||||||
|
GdkRegion *common_region;
|
||||||
|
|
||||||
|
/* make sure the border is invalidated */
|
||||||
|
common.x += 1;
|
||||||
|
common.y += 1;
|
||||||
|
common.width -= 2;
|
||||||
|
common.height -= 2;
|
||||||
|
|
||||||
|
common_region = gdk_region_rectangle (&common);
|
||||||
|
|
||||||
|
gdk_region_subtract (invalid_region, common_region);
|
||||||
|
gdk_region_destroy (common_region);
|
||||||
|
}
|
||||||
|
|
||||||
|
gdk_window_invalidate_region (tree_view->priv->bin_window, invalid_region, TRUE);
|
||||||
|
|
||||||
|
gdk_region_destroy (invalid_region);
|
||||||
|
|
||||||
|
tree_view->priv->rubber_band_x = x;
|
||||||
|
tree_view->priv->rubber_band_y = y;
|
||||||
|
|
||||||
|
gtk_tree_view_update_rubber_band_selection (tree_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_tree_view_paint_rubber_band (GtkTreeView *tree_view,
|
||||||
|
GdkRectangle *area)
|
||||||
|
{
|
||||||
|
cairo_t *cr;
|
||||||
|
GdkRectangle rect;
|
||||||
|
GdkRectangle rubber_rect;
|
||||||
|
|
||||||
|
rubber_rect.x = MIN (tree_view->priv->press_start_x, tree_view->priv->rubber_band_x);
|
||||||
|
rubber_rect.y = MIN (tree_view->priv->press_start_y, tree_view->priv->rubber_band_y) - tree_view->priv->dy;
|
||||||
|
rubber_rect.width = ABS (tree_view->priv->press_start_x - tree_view->priv->rubber_band_x) + 1;
|
||||||
|
rubber_rect.height = ABS (tree_view->priv->press_start_y - tree_view->priv->rubber_band_y) + 1;
|
||||||
|
|
||||||
|
if (!gdk_rectangle_intersect (&rubber_rect, area, &rect))
|
||||||
|
return;
|
||||||
|
|
||||||
|
cr = gdk_cairo_create (tree_view->priv->bin_window);
|
||||||
|
cairo_set_line_width (cr, 1.0);
|
||||||
|
|
||||||
|
cairo_set_source_rgba (cr,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.,
|
||||||
|
.25);
|
||||||
|
|
||||||
|
gdk_cairo_rectangle (cr, &rect);
|
||||||
|
cairo_clip (cr);
|
||||||
|
cairo_paint (cr);
|
||||||
|
|
||||||
|
cairo_set_source_rgb (cr,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].red / 65535.,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].green / 65535.,
|
||||||
|
GTK_WIDGET (tree_view)->style->fg[GTK_STATE_NORMAL].blue / 65535.);
|
||||||
|
|
||||||
|
cairo_rectangle (cr,
|
||||||
|
rubber_rect.x + 0.5, rubber_rect.y + 0.5,
|
||||||
|
rubber_rect.width - 1, rubber_rect.height - 1);
|
||||||
|
cairo_stroke (cr);
|
||||||
|
|
||||||
|
cairo_destroy (cr);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_tree_view_motion_bin_window (GtkWidget *widget,
|
gtk_tree_view_motion_bin_window (GtkWidget *widget,
|
||||||
GdkEventMotion *event)
|
GdkEventMotion *event)
|
||||||
@ -3457,8 +3826,26 @@ gtk_tree_view_motion_bin_window (GtkWidget *widget,
|
|||||||
if (tree_view->priv->tree == NULL)
|
if (tree_view->priv->tree == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_band_status == RUBBER_BAND_MAYBE_START)
|
||||||
|
{
|
||||||
|
gtk_grab_add (GTK_WIDGET (tree_view));
|
||||||
|
gtk_tree_view_update_rubber_band (tree_view);
|
||||||
|
|
||||||
|
tree_view->priv->rubber_band_status = RUBBER_BAND_ACTIVE;
|
||||||
|
}
|
||||||
|
else if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
|
||||||
|
{
|
||||||
|
gtk_tree_view_update_rubber_band (tree_view);
|
||||||
|
|
||||||
|
if (tree_view->priv->scroll_timeout == 0)
|
||||||
|
{
|
||||||
|
tree_view->priv->scroll_timeout = g_timeout_add (150, scroll_row_timeout, tree_view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* only check for an initiated drag when a button is pressed */
|
/* only check for an initiated drag when a button is pressed */
|
||||||
if (tree_view->priv->pressed_button >= 0)
|
if (tree_view->priv->pressed_button >= 0
|
||||||
|
&& !tree_view->priv->rubber_band_status)
|
||||||
gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
|
gtk_tree_view_maybe_begin_dragging_row (tree_view, event);
|
||||||
|
|
||||||
new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
|
new_y = TREE_WINDOW_Y_TO_RBTREE_Y(tree_view, event->y);
|
||||||
@ -4143,7 +4530,23 @@ gtk_tree_view_bin_expose (GtkWidget *widget,
|
|||||||
}
|
}
|
||||||
while (y_offset < event->area.height);
|
while (y_offset < event->area.height);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
|
||||||
|
{
|
||||||
|
GdkRectangle *rectangles;
|
||||||
|
gint n_rectangles;
|
||||||
|
|
||||||
|
gdk_region_get_rectangles (event->region,
|
||||||
|
&rectangles,
|
||||||
|
&n_rectangles);
|
||||||
|
|
||||||
|
while (n_rectangles--)
|
||||||
|
gtk_tree_view_paint_rubber_band (tree_view, &rectangles[n_rectangles]);
|
||||||
|
|
||||||
|
g_free (rectangles);
|
||||||
|
}
|
||||||
|
|
||||||
if (cursor_path)
|
if (cursor_path)
|
||||||
gtk_tree_path_free (cursor_path);
|
gtk_tree_path_free (cursor_path);
|
||||||
|
|
||||||
@ -5945,6 +6348,7 @@ remove_scroll_timeout (GtkTreeView *tree_view)
|
|||||||
tree_view->priv->scroll_timeout = 0;
|
tree_view->priv->scroll_timeout = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
check_model_dnd (GtkTreeModel *model,
|
check_model_dnd (GtkTreeModel *model,
|
||||||
GType required_iface,
|
GType required_iface,
|
||||||
@ -6025,6 +6429,9 @@ scroll_row_timeout (gpointer data)
|
|||||||
|
|
||||||
gtk_tree_view_vertical_autoscroll (tree_view);
|
gtk_tree_view_vertical_autoscroll (tree_view);
|
||||||
|
|
||||||
|
if (tree_view->priv->rubber_band_status == RUBBER_BAND_ACTIVE)
|
||||||
|
gtk_tree_view_update_rubber_band (tree_view);
|
||||||
|
|
||||||
GDK_THREADS_LEAVE ();
|
GDK_THREADS_LEAVE ();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -9289,7 +9696,6 @@ gtk_tree_view_real_select_cursor_parent (GtkTreeView *tree_view)
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
|
gtk_tree_view_search_entry_flush_timeout (GtkTreeView *tree_view)
|
||||||
{
|
{
|
||||||
@ -13735,6 +14141,49 @@ gtk_tree_view_get_hover_expand (GtkTreeView *tree_view)
|
|||||||
return tree_view->priv->hover_expand;
|
return tree_view->priv->hover_expand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_tree_view_set_rubber_banding:
|
||||||
|
* @tree_view: a #GtkTreeView
|
||||||
|
* @enable: %TRUE to enable rubber banding
|
||||||
|
*
|
||||||
|
* Enables or disables rubber banding in @tree_view. If the selection mode
|
||||||
|
* is #GTK_SELECTION_MULTIPLE, rubber banding will allow the user to select
|
||||||
|
* multiple rows by dragging the mouse.
|
||||||
|
*
|
||||||
|
* Since: 2.10
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
|
||||||
|
gboolean enable)
|
||||||
|
{
|
||||||
|
enable = enable != FALSE;
|
||||||
|
|
||||||
|
if (enable != tree_view->priv->rubber_banding_enable)
|
||||||
|
{
|
||||||
|
tree_view->priv->rubber_banding_enable = enable;
|
||||||
|
|
||||||
|
g_object_notify (G_OBJECT (tree_view), "rubber-banding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_tree_view_get_rubber_banding:
|
||||||
|
* @tree_view: a #GtkTreeView
|
||||||
|
*
|
||||||
|
* Returns whether rubber banding is turned on for @tree_view. If the
|
||||||
|
* selection mode is #GTK_SELECTION_MULTIPLE, rubber banding will allow the
|
||||||
|
* user to select multiple rows by dragging the mouse.
|
||||||
|
*
|
||||||
|
* Return value: %TRUE if rubber banding in @tree_view is enabled.
|
||||||
|
*
|
||||||
|
* Since: 2.10
|
||||||
|
**/
|
||||||
|
gboolean
|
||||||
|
gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view)
|
||||||
|
{
|
||||||
|
return tree_view->priv->rubber_banding_enable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_tree_view_get_row_separator_func:
|
* gtk_tree_view_get_row_separator_func:
|
||||||
* @tree_view: a #GtkTreeView
|
* @tree_view: a #GtkTreeView
|
||||||
|
@ -342,6 +342,9 @@ gboolean gtk_tree_view_get_hover_selection (GtkTreeView *tree_view);
|
|||||||
void gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
|
void gtk_tree_view_set_hover_expand (GtkTreeView *tree_view,
|
||||||
gboolean expand);
|
gboolean expand);
|
||||||
gboolean gtk_tree_view_get_hover_expand (GtkTreeView *tree_view);
|
gboolean gtk_tree_view_get_hover_expand (GtkTreeView *tree_view);
|
||||||
|
void gtk_tree_view_set_rubber_banding (GtkTreeView *tree_view,
|
||||||
|
gboolean enable);
|
||||||
|
gboolean gtk_tree_view_get_rubber_banding (GtkTreeView *tree_view);
|
||||||
|
|
||||||
GtkTreeViewRowSeparatorFunc gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view);
|
GtkTreeViewRowSeparatorFunc gtk_tree_view_get_row_separator_func (GtkTreeView *tree_view);
|
||||||
void gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view,
|
void gtk_tree_view_set_row_separator_func (GtkTreeView *tree_view,
|
||||||
|
Loading…
Reference in New Issue
Block a user