widget: Add gtk_widget_set_overflow()
authorBenjamin Otte <otte@redhat.com>
Fri, 8 Feb 2019 17:02:40 +0000 (18:02 +0100)
committerBenjamin Otte <otte@redhat.com>
Fri, 8 Feb 2019 17:26:42 +0000 (18:26 +0100)
This adds a simple abilities for widget implementations to clip their
content. See future commits for users of this.

docs/reference/gtk/gtk4-sections.txt
gtk/gtkenums.h
gtk/gtkwidget.c
gtk/gtkwidget.h
gtk/gtkwidgetprivate.h

index 27c18bb3e9a209629be3c27d955c64fb9269de49..1929eaf4a1b137d0fbac7609b53ec47e6cbe0afe 100644 (file)
@@ -4486,6 +4486,8 @@ gtk_widget_get_modifier_mask
 gtk_widget_insert_action_group
 gtk_widget_get_opacity
 gtk_widget_set_opacity
+gtk_widget_get_overflow
+gtk_widget_set_overflow
 gtk_widget_list_action_prefixes
 gtk_widget_get_action_group
 gtk_widget_measure
index e6ea7b3bb4afec3b2d6d99b041bfec407a575960..7eab7923e37c732226ed0cb9c5753712e17bfc60 100644 (file)
@@ -341,6 +341,23 @@ typedef enum
   GTK_ORIENTATION_VERTICAL
 } GtkOrientation;
 
+/**
+ * GtkOverflow:
+ * @GTK_OVERFLOW_VISIBLE: No change is applied. Content is drawn at the specified
+ *     position.
+ * @GTK_OVERFLOW_HIDDEN: Content is clipped to the bounds of the area. Content
+ *     outside the area is not drawn and cannot be interacted with.
+ *
+ * Defines how content overflowing a given area should be handled, such as
+ * with gtk_widget_set_overflow(). This property is modeled after the CSS overflow
+ * property, but implements it only partially.
+ */
+typedef enum
+{
+  GTK_OVERFLOW_VISIBLE,
+  GTK_OVERFLOW_HIDDEN
+} GtkOverflow;
+
 /**
  * GtkPackType:
  * @GTK_PACK_START: The child is packed into the start of the box
index 782888e310f57bceba68e256cd0fd9466059686e..db8434998d09730df8580b710eba2599c62c8747 100644 (file)
@@ -524,6 +524,7 @@ enum {
   PROP_TOOLTIP_TEXT,
   PROP_SURFACE,
   PROP_OPACITY,
+  PROP_OVERFLOW,
   PROP_HALIGN,
   PROP_VALIGN,
   PROP_MARGIN_START,
@@ -1305,6 +1306,19 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                            1.0,
                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkWidget:overflow:
+   *
+   * How content outside the widget's content area is treated.
+   */
+  widget_props[PROP_OVERFLOW] =
+      g_param_spec_enum ("overflow",
+                         P_("Overflow"),
+                         P_("How content outside the widget's content area is treated"),
+                         GTK_TYPE_OVERFLOW,
+                         GTK_OVERFLOW_VISIBLE,
+                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   /**
    * GtkWidget:scale-factor:
    *
@@ -2319,6 +2333,9 @@ gtk_widget_set_property (GObject         *object,
     case PROP_OPACITY:
       gtk_widget_set_opacity (widget, g_value_get_double (value));
       break;
+    case PROP_OVERFLOW:
+      gtk_widget_set_overflow (widget, g_value_get_enum (value));
+      break;
     case PROP_CSS_NAME:
       if (g_value_get_string (value) != NULL)
         gtk_css_node_set_name (priv->cssnode, g_intern_string (g_value_get_string (value)));
@@ -2459,6 +2476,9 @@ gtk_widget_get_property (GObject         *object,
     case PROP_OPACITY:
       g_value_set_double (value, gtk_widget_get_opacity (widget));
       break;
+    case PROP_OVERFLOW:
+      g_value_set_enum (value, gtk_widget_get_overflow (widget));
+      break;
     case PROP_SCALE_FACTOR:
       g_value_set_int (value, gtk_widget_get_scale_factor (widget));
       break;
@@ -11179,6 +11199,8 @@ gtk_widget_pick (GtkWidget *widget,
                  gdouble    x,
                  gdouble    y)
 {
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
 
   if (gtk_widget_get_pass_through (widget) ||
@@ -11186,6 +11208,31 @@ gtk_widget_pick (GtkWidget *widget,
       !_gtk_widget_is_drawable (widget))
     return NULL;
 
+  switch (priv->overflow)
+    {
+    default:
+    case GTK_OVERFLOW_VISIBLE:
+      break;
+
+    case GTK_OVERFLOW_HIDDEN:
+      {
+        GtkBorder margin, border, padding;
+        GtkCssStyle *style;
+
+        style = gtk_css_node_get_style (priv->cssnode);
+        get_box_margin (style, &margin);
+        get_box_border (style, &border);
+        get_box_padding (style, &padding);
+
+        if (x < -padding.left ||
+            y < -padding.top  ||
+            x >= priv->allocation.width - margin.left - margin.right - border.left - border.right - padding.left ||
+            y >= priv->allocation.height - margin.top - margin.bottom - border.top - border.bottom - padding.top)
+          return NULL;
+      }
+      break;
+    }
+
   return GTK_WIDGET_GET_CLASS (widget)->pick (widget, x, y);
 }
 
@@ -11574,6 +11621,55 @@ gtk_widget_get_opacity (GtkWidget *widget)
   return priv->user_alpha / 255.0;
 }
 
+/**
+ * gtk_widget_set_overflow:
+ * @self: a #GtkWidget
+ * @overflow: desired overflow
+ *
+ * Sets how @self treats content that is drawn outside the widget's content area.
+ * See the definition of #GtkOverflow for details.
+ *
+ * This setting is provided for widget implementations and should not be used by
+ * application code.
+ *
+ * The default value is %GTK_OVERFLOW_VISIBLE.
+ **/
+void
+gtk_widget_set_overflow (GtkWidget   *self,
+                         GtkOverflow  overflow)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
+
+  g_return_if_fail (GTK_IS_WIDGET (self));
+
+  if (priv->overflow == overflow)
+    return;
+
+  priv->overflow = overflow;
+
+  gtk_widget_queue_draw (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), widget_props[PROP_OVERFLOW]);
+}
+
+/**
+ * gtk_widget_get_overflow:
+ * @self: a #GtkWidget
+ *
+ * Returns the value set via gtk_widget_set_overflow().
+ *
+ * Returns: The widget's overflow.
+ **/
+GtkOverflow
+gtk_widget_get_overflow (GtkWidget *self)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (self);
+
+  g_return_val_if_fail (GTK_IS_WIDGET (self), GTK_OVERFLOW_VISIBLE);
+
+  return priv->overflow;
+}
+
 /**
  * gtk_widget_send_focus_change:
  * @widget: a #GtkWidget
@@ -12959,7 +13055,21 @@ gtk_widget_create_render_node (GtkWidget   *widget,
 
   /* Offset to content allocation */
   gtk_snapshot_offset (snapshot, margin.left + padding.left + border.left, margin.top + border.top + padding.top);
+
+  if (priv->overflow == GTK_OVERFLOW_HIDDEN)
+    {
+      gtk_snapshot_push_clip (snapshot,
+                              &GRAPHENE_RECT_INIT (- padding.left,
+                                                   - padding.top,
+                                                   allocation.width - margin.left - margin.right - border.left  - border.right,
+                                                   allocation.height - margin.top  - margin.bottom - border.top  - border.bottom));
+    }
+
   klass->snapshot (widget, snapshot);
+
+  if (priv->overflow == GTK_OVERFLOW_HIDDEN)
+    gtk_snapshot_pop (snapshot);
+
   gtk_snapshot_offset (snapshot, - (padding.left + border.left), -(border.top + padding.top));
 
   gtk_css_style_snapshot_outline (style,
index a9aba23eb75ce39daf2f8a94e5610187dfa4893a..9b89f70246f58e066c368a3d121720f18af2155f 100644 (file)
@@ -631,6 +631,12 @@ void       gtk_widget_set_opacity         (GtkWidget           *widget,
                                            double               opacity);
 GDK_AVAILABLE_IN_ALL
 double     gtk_widget_get_opacity         (GtkWidget           *widget);
+GDK_AVAILABLE_IN_ALL
+void         gtk_widget_set_overflow      (GtkWidget           *widget,
+                                           GtkOverflow          overflow);
+GDK_AVAILABLE_IN_ALL
+GtkOverflow  gtk_widget_get_overflow      (GtkWidget           *widget);
+
 
 GDK_AVAILABLE_IN_ALL
 GtkWidget*   gtk_widget_get_toplevel    (GtkWidget      *widget);
index c70a5e9e620ab8dcbf855165d5716db6aeadae30..26c33ba0bc2bbac1d30bd89d865c5377126c98f3 100644 (file)
@@ -99,6 +99,7 @@ struct _GtkWidgetPrivate
   guint   halign              : 4;
   guint   valign              : 4;
 
+  GtkOverflow overflow;
   guint8 alpha;
   guint8 user_alpha;