[gtk/prop-list: 67/70] wip: rubberband drawing



commit 09f21664cc52adb35bb2a4747b9be02695f733f0
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Dec 21 19:07:11 2019 -0500

    wip: rubberband drawing
    
    Nothing to see here yet. This just adds some
    disconnected code for drawing a rubberband selection
    in GtkListBase.

 gtk/gtklistbase.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)
---
diff --git a/gtk/gtklistbase.c b/gtk/gtklistbase.c
index fde6ff498b..401b87b616 100644
--- a/gtk/gtklistbase.c
+++ b/gtk/gtklistbase.c
@@ -29,6 +29,12 @@
 #include "gtkscrollable.h"
 #include "gtksingleselection.h"
 #include "gtktypebuiltins.h"
+#include "gtkgestureclick.h"
+#include "gtkeventcontrollermotion.h"
+#include "gtkwidgetprivate.h"
+#include "gtkcssnodeprivate.h"
+#include "gtkstylecontextprivate.h"
+#include "gtksnapshot.h"
 
 typedef struct _GtkListBasePrivate GtkListBasePrivate;
 
@@ -51,6 +57,10 @@ struct _GtkListBasePrivate
   GtkListItemTracker *selected;
   /* the item that has input focus */
   GtkListItemTracker *focus;
+
+  gboolean rb_ongoing;
+  double rb_x1, rb_y1, rb_x2, rb_y2;
+  GtkCssNode *rb_node;
 };
 
 enum
@@ -1059,6 +1069,20 @@ gtk_list_base_add_custom_move_binding (GtkBindingSet      *binding_set,
                                   NULL, NULL);
 }
 
+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)
 {
@@ -1068,6 +1092,7 @@ 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;
@@ -1187,11 +1212,128 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
   gtk_binding_entry_add_action (binding_set, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
 }
 
+static void
+gtk_list_base_start_rubberbanding (GtkListBase *self,
+                                   double       x,
+                                   double       y)
+{
+  GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+  GtkCssNode *widget_node;
+
+  if (priv->rb_ongoing)
+    return;
+
+  priv->rb_x1 = priv->rb_x2 = x + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
+  priv->rb_y1 = priv->rb_y2 = y + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
+
+  priv->rb_ongoing = TRUE;
+
+  widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
+  priv->rb_node = gtk_css_node_new ();
+  gtk_css_node_set_name (priv->rb_node, I_("rubberband"));
+  gtk_css_node_set_parent (priv->rb_node, widget_node);
+  gtk_css_node_set_state (priv->rb_node, gtk_css_node_get_state (widget_node));
+  g_object_unref (priv->rb_node);
+}
+
+static void
+gtk_list_base_stop_rubberbanding (GtkListBase *self)
+{
+  GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+
+  if (!priv->rb_ongoing)
+    return;
+
+  priv->rb_ongoing = FALSE;
+  gtk_css_node_set_parent (priv->rb_node, NULL);
+  priv->rb_node = NULL;
+
+  gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+static void
+gtk_list_base_update_rubberband (GtkListBase *self,
+                                 double       x,
+                                 double       y)
+{
+  GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+
+  if (!priv->rb_ongoing)
+    return;
+
+  priv->rb_x2 = x + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
+  priv->rb_y2 = y + gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
+
+  gtk_widget_queue_draw (GTK_WIDGET (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;
+
+  if (!priv->rb_ongoing)
+    return;
+
+  rect.x = MIN (priv->rb_x1, priv->rb_x2);
+  rect.y = MIN (priv->rb_y1, priv->rb_y2);
+  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->rb_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
+gtk_list_base_button_press (GtkGestureClick *gesture,
+                            int              n_press,
+                            double           x,
+                            double           y,
+                            GtkListBase     *self)
+{
+  gtk_list_base_start_rubberbanding (self, x, y);
+}
+
+static void
+gtk_list_base_button_release (GtkGestureClick *gesture,
+                              int              n_press,
+                              double           x,
+                              double           y,
+                              GtkListBase     *self)
+{
+  gtk_list_base_stop_rubberbanding (self);
+}
+
+static void
+gtk_list_base_motion (GtkEventController *controller,
+                      double              x,
+                      double              y,
+                      GtkListBase        *self)
+{
+  gtk_list_base_update_rubberband (self, x, y);
+}
+
 static void
 gtk_list_base_init_real (GtkListBase      *self,
                          GtkListBaseClass *g_class)
 {
   GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
+  GtkGesture *gesture;
+  GtkEventController *controller;
 
   priv->item_manager = gtk_list_item_manager_new_for_size (GTK_WIDGET (self),
                                                            g_class->list_item_name,
@@ -1210,6 +1352,15 @@ gtk_list_base_init_real (GtkListBase      *self,
   priv->orientation = GTK_ORIENTATION_VERTICAL;
 
   gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
+
+  gesture = gtk_gesture_click_new ();
+  g_signal_connect (gesture, "pressed", G_CALLBACK (gtk_list_base_button_press), self);
+  g_signal_connect (gesture, "released", G_CALLBACK (gtk_list_base_button_release), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
+
+  controller = gtk_event_controller_motion_new ();
+  g_signal_connect (controller, "motion", G_CALLBACK (gtk_list_base_motion), self);
+  gtk_widget_add_controller (GTK_WIDGET (self), controller);
 }
 
 static int


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]