summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2015-06-08 16:28:32 +0200
committerAlexander Larsson <alexl@redhat.com>2015-06-15 10:56:45 +0200
commit76ba5a03b94157423bb37039bc214eedf29312b3 (patch)
tree2e8248fabd5e957083ac1f6d76854ee6e801b09e
parent4c3eece6638aa36fbcd8379109dcb4e27323a306 (diff)
downloadgtk+-76ba5a03b94157423bb37039bc214eedf29312b3.tar.gz
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
-rw-r--r--gtk/gtkoverlay.c199
-rw-r--r--gtk/gtkoverlay.h5
2 files changed, 203 insertions, 1 deletions
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
index c7c3e27887..0760f7f072 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 32e3f391d3..dfbd0423b9 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