listbase: Use a widget for the rubberband

We no longer need to juggle manual css nodes. Just create
a widget for the rubberband, and update its allocation
as we rubberband.
This commit is contained in:
Matthias Clasen 2020-06-02 12:42:53 -04:00
parent 7dc458d925
commit 14d11ebcab
4 changed files with 44 additions and 75 deletions

View File

@ -713,6 +713,8 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
int x, y;
guint i;
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (widget));
orientation = gtk_list_base_get_orientation (GTK_LIST_BASE (self));
scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), orientation);
opposite_orientation = OPPOSITE_ORIENTATION (orientation);

View File

@ -30,10 +30,10 @@
#include "gtktypebuiltins.h"
#include "gtkgesturedrag.h"
#include "gtkwidgetprivate.h"
#include "gtkcssnodeprivate.h"
#include "gtkstylecontextprivate.h"
#include "gtksnapshot.h"
#include "gtkmultiselection.h"
#include "gtkgizmoprivate.h"
typedef struct _GtkListBasePrivate GtkListBasePrivate;
@ -58,13 +58,12 @@ struct _GtkListBasePrivate
GtkListItemTracker *focus;
gboolean enable_rubberband;
gboolean doing_rubberband;
double rb_x1;
double rb_y1;
double rb_x2;
double rb_y2;
GtkGesture *drag_gesture;
GtkCssNode *rubberband_node;
GtkWidget *rubberband;
GtkSelectionModel *old_selection;
gboolean modify;
gboolean extend;
@ -1083,20 +1082,6 @@ gtk_list_base_add_custom_move_binding (GtkWidgetClass *widget_class,
"(bbb)", TRUE, TRUE, TRUE);
}
static void gtk_list_base_snapshot_rubberband (GtkListBase *self,
GtkSnapshot *snapshot);
static void
gtk_list_base_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkListBase *self = GTK_LIST_BASE (widget);
GTK_WIDGET_CLASS (gtk_list_base_parent_class)->snapshot (widget, snapshot);
gtk_list_base_snapshot_rubberband (self, snapshot);
}
static void
gtk_list_base_class_init (GtkListBaseClass *klass)
{
@ -1105,7 +1090,6 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
gpointer iface;
widget_class->focus = gtk_list_base_focus;
widget_class->snapshot = gtk_list_base_snapshot;
gobject_class->dispose = gtk_list_base_dispose;
gobject_class->get_property = gtk_list_base_get_property;
@ -1239,7 +1223,7 @@ autoscroll_cb (GtkWidget *widget,
value = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
gtk_adjustment_set_value (priv->adjustment[GTK_ORIENTATION_VERTICAL], value + priv->autoscroll_delta_y);
if (priv->doing_rubberband)
if (priv->rubberband)
{
priv->rb_x2 += priv->autoscroll_delta_x;
priv->rb_y2 += priv->autoscroll_delta_y;
@ -1277,6 +1261,32 @@ remove_autoscroll (GtkListBase *self)
}
}
void
gtk_list_base_allocate_rubberband (GtkListBase *self)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
GdkRectangle rect;
double x, y;
int min, nat;
if (!priv->rubberband)
return;
gtk_widget_measure (priv->rubberband,
GTK_ORIENTATION_HORIZONTAL, -1,
&min, &nat, NULL, NULL);
x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
rect.x = MIN (priv->rb_x1, priv->rb_x2) - x;
rect.y = MIN (priv->rb_y1, priv->rb_y2) - y;
rect.width = ABS (priv->rb_x1 - priv->rb_x2) + 1;
rect.height = ABS (priv->rb_y1 - priv->rb_y2) + 1;
gtk_widget_size_allocate (priv->rubberband, &rect, -1);
}
static void
gtk_list_base_start_rubberband (GtkListBase *self,
double x,
@ -1285,11 +1295,10 @@ gtk_list_base_start_rubberband (GtkListBase *self,
gboolean extend)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
GtkCssNode *widget_node;
double value_x, value_y;
GtkSelectionModel *selection;
if (priv->doing_rubberband)
if (priv->rubberband)
return;
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
@ -1301,20 +1310,14 @@ gtk_list_base_start_rubberband (GtkListBase *self,
priv->modify = modify;
priv->extend = extend;
widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
priv->rubberband_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->rubberband_node,
g_quark_from_static_string ("rubberband"));
gtk_css_node_set_parent (priv->rubberband_node, widget_node);
gtk_css_node_set_state (priv->rubberband_node, gtk_css_node_get_state (widget_node));
g_object_unref (priv->rubberband_node);
priv->rubberband = gtk_gizmo_new ("rubberband",
NULL, NULL, NULL, NULL, NULL, NULL);
gtk_widget_set_parent (priv->rubberband, GTK_WIDGET (self));
selection = gtk_list_item_manager_get_model (priv->item_manager);
if (modify)
priv->old_selection = GTK_SELECTION_MODEL (gtk_multi_selection_copy (selection));
priv->doing_rubberband = TRUE;
}
static void
@ -1322,13 +1325,10 @@ gtk_list_base_stop_rubberband (GtkListBase *self)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
if (!priv->doing_rubberband)
if (!priv->rubberband)
return;
priv->doing_rubberband = FALSE;
gtk_css_node_set_parent (priv->rubberband_node, NULL);
priv->rubberband_node = NULL;
g_clear_pointer (&priv->rubberband, gtk_widget_unparent);
g_clear_object (&priv->old_selection);
remove_autoscroll (self);
@ -1347,7 +1347,7 @@ gtk_list_base_update_rubberband (GtkListBase *self,
double value_x, value_y, page_size, upper;
double delta_x, delta_y;
if (!priv->doing_rubberband)
if (!priv->rubberband)
return;
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
@ -1392,17 +1392,11 @@ gtk_list_base_update_rubberband_selection (GtkListBase *self)
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
GdkRectangle rect;
GdkRectangle alloc;
double value_x, value_y;
GtkSelectionModel *model;
GtkListItemManagerItem *item;
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
rect.x = MIN (priv->rb_x1, priv->rb_x2) - value_x;
rect.y = MIN (priv->rb_y1, priv->rb_y2) - value_y;
rect.width = ABS (priv->rb_x1 - priv->rb_x2) + 1;
rect.height = ABS (priv->rb_y1 - priv->rb_y2) + 1;
gtk_list_base_allocate_rubberband (self);
gtk_widget_get_allocation (priv->rubberband, &rect);
model = gtk_list_item_manager_get_model (priv->item_manager);
@ -1435,37 +1429,6 @@ gtk_list_base_update_rubberband_selection (GtkListBase *self)
}
}
static void
gtk_list_base_snapshot_rubberband (GtkListBase *self,
GtkSnapshot *snapshot)
{
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
GtkStyleContext *context;
GdkRectangle rect;
double value_x, value_y;
if (!priv->doing_rubberband)
return;
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
rect.x = MIN (priv->rb_x1, priv->rb_x2) - value_x;
rect.y = MIN (priv->rb_y1, priv->rb_y2) - value_y;
rect.width = ABS (priv->rb_x1 - priv->rb_x2) + 1;
rect.height = ABS (priv->rb_y1 - priv->rb_y2) + 1;
context = gtk_widget_get_style_context (GTK_WIDGET (self));
gtk_style_context_save_to_node (context, priv->rubberband_node);
gtk_snapshot_render_background (snapshot, context, rect.x, rect.y, rect.width, rect.height);
gtk_snapshot_render_frame (snapshot, context, rect.x, rect.y, rect.width, rect.height);
gtk_style_context_restore (context);
}
static void
get_selection_modifiers (GtkGesture *gesture,
gboolean *modify,

View File

@ -103,4 +103,6 @@ void gtk_list_base_set_enable_rubberband (GtkListBase
gboolean enable);
gboolean gtk_list_base_get_enable_rubberband (GtkListBase *self);
void gtk_list_base_allocate_rubberband (GtkListBase *self);
#endif /* __GTK_LIST_BASE_PRIVATE_H__ */

View File

@ -516,6 +516,8 @@ gtk_list_view_size_allocate (GtkWidget *widget,
GtkOrientation orientation, opposite_orientation;
GtkScrollablePolicy scroll_policy;
gtk_list_base_allocate_rubberband (GTK_LIST_BASE (self));
orientation = gtk_list_base_get_orientation (GTK_LIST_BASE (self));
opposite_orientation = OPPOSITE_ORIENTATION (orientation);
scroll_policy = gtk_list_base_get_scroll_policy (GTK_LIST_BASE (self), orientation);