[gtk+] overlay: Add reorder_overlay()



commit 76ba5a03b94157423bb37039bc214eedf29312b3
Author: Alexander Larsson <alexl redhat com>
Date:   Mon Jun 8 16:28:32 2015 +0200

    overlay: Add reorder_overlay()
    
    This allows you to control the z-ordering of overlay children
    
    https://bugzilla.gnome.org/show_bug.cgi?id=750568
    
    https://bugs.freedesktop.org/show_bug.cgi?id=90917

 gtk/gtkoverlay.c |  199 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkoverlay.h |    5 ++
 2 files changed, 203 insertions(+), 1 deletions(-)
---
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
index c7c3e27..0760f7f 100644
--- a/gtk/gtkoverlay.c
+++ b/gtk/gtkoverlay.c
@@ -71,6 +71,12 @@ enum {
   LAST_SIGNAL
 };
 
+enum
+{
+  CHILD_PROP_0,
+  CHILD_PROP_INDEX
+};
+
 static guint signals[LAST_SIGNAL] = { 0 };
 
 static void gtk_overlay_buildable_init (GtkBuildableIface *iface);
@@ -293,6 +299,9 @@ gtk_overlay_child_allocate (GtkOverlay      *overlay,
 
   if (gtk_widget_get_mapped (GTK_WIDGET (overlay)))
     {
+      /* Note: This calls show every size allocation, which makes
+       * us keep the z-order of the chilren, as gdk_window_show()
+       * does an implicit raise. */
       if (gtk_widget_get_visible (child->widget))
         gdk_window_show (child->window);
       else if (gdk_window_is_visible (child->window))
@@ -485,7 +494,9 @@ gtk_overlay_remove (GtkContainer *container,
   GtkOverlayPrivate *priv = GTK_OVERLAY (container)->priv;
   GtkOverlayChild *child;
   GSList *children;
+  gboolean removed;
 
+  removed = FALSE;
   for (children = priv->children; children; children = children->next)
     {
       child = children->data;
@@ -503,13 +514,94 @@ gtk_overlay_remove (GtkContainer *container,
           priv->children = g_slist_delete_link (priv->children, children);
           g_slice_free (GtkOverlayChild, child);
 
-          return;
+          removed = TRUE;
         }
+      else if (removed)
+        gtk_widget_child_notify (child->widget, "index");
     }
 
   GTK_CONTAINER_CLASS (gtk_overlay_parent_class)->remove (container, widget);
 }
 
+/**
+ * gtk_overlay_reorder_overlay:
+ * @overlay: a #GtkOverlay
+ * @child: the overlaid #GtkWidget to move
+ * @index: the new index for @child in the list of overlay children
+ *   of @overlay, starting from 0. If negative, indicates the end of
+ *   the list
+ *
+ * Moves @child to a new @index in the list of @overlay children.
+ * The list contains overlays in the order that these were
+ * added to @overlay.
+ *
+ * A widget’s index in the @overlay children list determines which order
+ * the children are drawn if they overlap. The first child is drawn at
+ * the bottom. It also affects the default focus chain order.
+ */
+void
+gtk_overlay_reorder_overlay (GtkOverlay     *overlay,
+                            GtkWidget      *child,
+                            gint            index)
+{
+  GtkOverlayPrivate *priv;
+  GSList *old_link;
+  GSList *new_link;
+  GSList *l;
+  GtkOverlayChild *child_info = NULL;
+  gint old_index, i;
+
+  g_return_if_fail (GTK_IS_OVERLAY (overlay));
+  g_return_if_fail (GTK_IS_WIDGET (child));
+
+  priv = GTK_OVERLAY (overlay)->priv;
+
+  old_link = priv->children;
+  old_index = 0;
+  while (old_link)
+    {
+      child_info = old_link->data;
+      if (child_info->widget == child)
+       break;
+
+      old_link = old_link->next;
+      old_index++;
+    }
+
+  g_return_if_fail (old_link != NULL);
+
+  if (index < 0)
+    {
+      new_link = NULL;
+      index = g_slist_length (priv->children) - 1;
+    }
+  else
+    {
+      new_link = g_slist_nth (priv->children, index);
+      index = MIN (index, g_slist_length (priv->children) - 1);
+    }
+
+  if (index == old_index)
+    return;
+
+  priv->children = g_slist_delete_link (priv->children, old_link);
+  priv->children = g_slist_insert_before (priv->children, new_link, child_info);
+
+  for (i = 0, l = priv->children; l != NULL; l = l->next, i++)
+    {
+      GtkOverlayChild *info = l->data;
+      if ((i < index && i < old_index) ||
+          (i > index && i > old_index))
+        continue;
+      gtk_widget_child_notify (info->widget, "index");
+    }
+
+  if (gtk_widget_get_visible (child) &&
+      gtk_widget_get_visible (GTK_WIDGET (overlay)))
+    gtk_widget_queue_resize (GTK_WIDGET (overlay));
+}
+
+
 static void
 gtk_overlay_forall (GtkContainer *overlay,
                     gboolean      include_internals,
@@ -535,6 +627,101 @@ gtk_overlay_forall (GtkContainer *overlay,
     }
 }
 
+static GtkOverlayChild *
+gtk_overlay_get_overlay_child (GtkOverlay *overlay,
+                              GtkWidget *child)
+{
+  GtkOverlayPrivate *priv = GTK_OVERLAY (overlay)->priv;
+  GtkOverlayChild *child_info;
+  GSList *children;
+
+  for (children = priv->children; children; children = children->next)
+    {
+      child_info = children->data;
+
+      if (child_info->widget == child)
+       return child_info;
+    }
+
+  return NULL;
+}
+
+static void
+gtk_overlay_set_child_property (GtkContainer *container,
+                               GtkWidget    *child,
+                               guint         property_id,
+                               const GValue *value,
+                               GParamSpec   *pspec)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (container);
+  GtkOverlayChild *child_info;
+  GtkWidget *main_widget;
+
+  main_widget = gtk_bin_get_child (GTK_BIN (overlay));
+  if (child == main_widget)
+    child_info = NULL;
+  else
+    {
+      child_info = gtk_overlay_get_overlay_child (overlay, child);
+      if (child_info == NULL)
+       {
+         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+         return;
+       }
+    }
+
+  switch (property_id)
+    {
+    case CHILD_PROP_INDEX:
+      if (child_info != NULL)
+       gtk_overlay_reorder_overlay (GTK_OVERLAY (container),
+                                    child,
+                                    g_value_get_int (value));
+      break;
+
+    default:
+      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_overlay_get_child_property (GtkContainer *container,
+                               GtkWidget    *child,
+                               guint         property_id,
+                               GValue       *value,
+                               GParamSpec   *pspec)
+{
+  GtkOverlay *overlay = GTK_OVERLAY (container);
+  GtkOverlayPrivate *priv = GTK_OVERLAY (overlay)->priv;
+  GtkOverlayChild *child_info;
+  GtkWidget *main_widget;
+
+  main_widget = gtk_bin_get_child (GTK_BIN (overlay));
+  if (child == main_widget)
+    child_info = NULL;
+  else
+    {
+      child_info = gtk_overlay_get_overlay_child (overlay, child);
+      if (child_info == NULL)
+       {
+         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+         return;
+       }
+    }
+
+  switch (property_id)
+    {
+    case CHILD_PROP_INDEX:
+      g_value_set_int (value, g_slist_index (priv->children, child_info));
+      break;
+    default:
+      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
+      break;
+    }
+}
+
+
 static void
 gtk_overlay_class_init (GtkOverlayClass *klass)
 {
@@ -550,9 +737,18 @@ gtk_overlay_class_init (GtkOverlayClass *klass)
 
   container_class->remove = gtk_overlay_remove;
   container_class->forall = gtk_overlay_forall;
+  container_class->set_child_property = gtk_overlay_set_child_property;
+  container_class->get_child_property = gtk_overlay_get_child_property;
 
   klass->get_child_position = gtk_overlay_get_child_position;
 
+  gtk_container_class_install_child_property (container_class, CHILD_PROP_INDEX,
+                                             g_param_spec_int ("index",
+                                                               P_("Index"),
+                                                               P_("The index of the overlay in the parent, 
-1 for the main child"),
+                                                               -1, G_MAXINT, 0,
+                                                               GTK_PARAM_READWRITE));
+
   /**
    * GtkOverlay::get-child-position:
    * @overlay: the #GtkOverlay
@@ -669,4 +865,5 @@ gtk_overlay_add_overlay (GtkOverlay *overlay,
   else
     gtk_widget_set_parent (widget, GTK_WIDGET (overlay));
 
+  gtk_widget_child_notify (widget, "index");
 }
diff --git a/gtk/gtkoverlay.h b/gtk/gtkoverlay.h
index 32e3f39..dfbd042 100644
--- a/gtk/gtkoverlay.h
+++ b/gtk/gtkoverlay.h
@@ -83,6 +83,11 @@ GtkWidget *gtk_overlay_new         (void);
 GDK_AVAILABLE_IN_3_2
 void       gtk_overlay_add_overlay (GtkOverlay *overlay,
                                     GtkWidget  *widget);
+GDK_AVAILABLE_IN_3_18
+void       gtk_overlay_reorder_overlay (GtkOverlay     *overlay,
+                                       GtkWidget      *child,
+                                       gint            position);
+
 
 G_END_DECLS
 


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