summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimm Bäder <mail@baedert.org>2017-04-05 19:57:11 +0200
committerTimm Bäder <mail@baedert.org>2017-04-24 21:52:10 +0200
commit6c808fe6a08b27b4d5cded260b20ae591464f735 (patch)
treefd0b6b2cf015a0f1080495175f8a1298c26e29e8
parent72ab59a1af6596a70ce7730c1e2991df58207b2c (diff)
downloadgtk+-6c808fe6a08b27b4d5cded260b20ae591464f735.tar.gz
widget: Add gtk_widget_insert_before/after
To insert a widget into the widget tree before or after a child widget of the soon-to-be parent.
-rw-r--r--docs/reference/gtk/gtk4-sections.txt2
-rw-r--r--gtk/gtkwidget.c200
-rw-r--r--gtk/gtkwidget.h8
3 files changed, 177 insertions, 33 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index df8b22117f..84229d0a45 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -4647,6 +4647,8 @@ gtk_widget_get_next_sibling
gtk_widget_get_prev_sibling
gtk_widget_get_first_child
gtk_widget_get_last_child
+gtk_widget_insert_before
+gtk_widget_insert_after
<SUBSECTION>
gtk_widget_get_path
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index eb3761a495..3eb573149e 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -8374,37 +8374,27 @@ gtk_widget_is_sensitive (GtkWidget *widget)
return !(widget->priv->state_flags & GTK_STATE_FLAG_INSENSITIVE);
}
-/**
- * gtk_widget_set_parent:
- * @widget: a #GtkWidget
- * @parent: parent container
- *
- * This function is useful only when implementing subclasses of
- * #GtkContainer.
- * Sets the container as the parent of @widget, and takes care of
- * some details such as updating the state and style of the child
- * to reflect its new location. The opposite function is
- * gtk_widget_unparent().
- **/
-void
-gtk_widget_set_parent (GtkWidget *widget,
- GtkWidget *parent)
+
+/* Insert @widget into the children list of @parent,
+ * after @previous_child */
+static void
+gtk_widget_reposition_after (GtkWidget *widget,
+ GtkWidget *parent,
+ GtkWidget *previous_sibling)
{
GtkStateFlags parent_flags;
- GtkWidgetPrivate *priv;
+ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+ GtkWidget *prev_parent;
GtkStateData data;
- g_return_if_fail (GTK_IS_WIDGET (widget));
- g_return_if_fail (GTK_IS_WIDGET (parent));
- g_return_if_fail (widget != parent);
+ prev_parent = priv->parent;
- priv = widget->priv;
-
- if (priv->parent != NULL)
+ if (priv->parent != NULL && priv->parent != parent)
{
g_warning ("Can't set a parent on widget which has a parent");
return;
}
+
if (_gtk_widget_is_toplevel (widget))
{
g_warning ("Can't set a parent on a toplevel widget");
@@ -8421,14 +8411,53 @@ gtk_widget_set_parent (GtkWidget *widget,
gtk_widget_push_verify_invariants (widget);
priv->parent = parent;
- if (parent)
+
+ if (previous_sibling)
{
- priv->prev_sibling = parent->priv->last_child;
- if (parent->priv->last_child)
- parent->priv->last_child->priv->next_sibling = widget;
- parent->priv->last_child = widget;
- if (!parent->priv->first_child)
- parent->priv->first_child = widget;
+ if (previous_sibling->priv->next_sibling)
+ previous_sibling->priv->next_sibling->priv->prev_sibling = widget;
+
+ if (priv->prev_sibling)
+ priv->prev_sibling->priv->next_sibling = priv->next_sibling;
+
+ if (priv->next_sibling)
+ priv->next_sibling->priv->prev_sibling = priv->prev_sibling;
+
+
+ if (parent->priv->first_child == widget)
+ parent->priv->first_child = priv->next_sibling;
+
+ if (parent->priv->last_child == widget)
+ parent->priv->last_child = priv->prev_sibling;
+
+ priv->prev_sibling = previous_sibling;
+ priv->next_sibling = previous_sibling->priv->next_sibling;
+ previous_sibling->priv->next_sibling = widget;
+
+ if (parent->priv->last_child == previous_sibling)
+ parent->priv->last_child = widget;
+ else if (parent->priv->last_child == widget)
+ parent->priv->last_child = priv->next_sibling;
+ }
+ else
+ {
+ /* Beginning */
+ if (parent->priv->last_child == widget)
+ {
+ parent->priv->last_child = priv->prev_sibling;
+ if (priv->prev_sibling)
+ priv->prev_sibling->priv->next_sibling = NULL;
+ }
+
+ priv->prev_sibling = NULL;
+ priv->next_sibling = parent->priv->first_child;
+ if (parent->priv->first_child)
+ parent->priv->first_child->priv->prev_sibling = widget;
+
+ parent->priv->first_child = widget;
+
+ if (parent->priv->last_child == NULL)
+ parent->priv->last_child = widget;
}
parent_flags = _gtk_widget_get_state_flags (parent);
@@ -8440,7 +8469,12 @@ gtk_widget_set_parent (GtkWidget *widget,
gtk_widget_propagate_state (widget, &data);
if (gtk_css_node_get_parent (widget->priv->cssnode) == NULL)
- gtk_css_node_set_parent (widget->priv->cssnode, parent->priv->cssnode);
+ {
+ gtk_css_node_insert_after (parent->priv->cssnode,
+ priv->cssnode,
+ previous_sibling ? previous_sibling->priv->cssnode : NULL);
+ }
+
if (priv->context)
gtk_style_context_set_parent (priv->context,
_gtk_widget_get_style_context (parent));
@@ -8448,7 +8482,7 @@ gtk_widget_set_parent (GtkWidget *widget,
_gtk_widget_update_parent_muxer (widget);
g_signal_emit (widget, widget_signals[PARENT_SET], 0, NULL);
- if (priv->parent->priv->anchored)
+ if (priv->parent->priv->anchored && prev_parent == NULL)
_gtk_widget_propagate_hierarchy_changed (widget, NULL);
g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_PARENT]);
@@ -8461,8 +8495,8 @@ gtk_widget_set_parent (GtkWidget *widget,
_gtk_widget_get_visible (widget))
{
if (_gtk_widget_get_child_visible (widget) &&
- _gtk_widget_get_mapped (priv->parent))
- gtk_widget_map (widget);
+ _gtk_widget_get_mapped (priv->parent))
+ gtk_widget_map (widget);
gtk_widget_queue_resize (priv->parent);
}
@@ -8489,6 +8523,31 @@ gtk_widget_set_parent (GtkWidget *widget,
}
/**
+ * gtk_widget_set_parent:
+ * @widget: a #GtkWidget
+ * @parent: parent container
+ *
+ * This function is useful only when implementing subclasses of
+ * #GtkContainer.
+ * Sets the container as the parent of @widget, and takes care of
+ * some details such as updating the state and style of the child
+ * to reflect its new location. The opposite function is
+ * gtk_widget_unparent().
+ **/
+void
+gtk_widget_set_parent (GtkWidget *widget,
+ GtkWidget *parent)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GTK_IS_WIDGET (parent));
+ g_return_if_fail (_gtk_widget_get_parent (widget) == NULL);
+
+ gtk_widget_reposition_after (widget,
+ parent,
+ _gtk_widget_get_last_child (parent));
+}
+
+/**
* gtk_widget_get_parent:
* @widget: a #GtkWidget
*
@@ -15634,6 +15693,81 @@ gtk_widget_get_prev_sibling (GtkWidget *widget)
return widget->priv->prev_sibling;
}
+/*
+ * @widget: a #GtkWidget
+ * @parent: the parent #GtkWidget to insert @widget into
+ * @previous_child: (nullable): the new previous sibling of @widget
+ *
+ * Inserts @widget into the child widget list of @parent.
+ * It will be placed after @previous_child, or at the beginning if @previous_child is %NULL.
+ *
+ * After calling this function, gtk_widget_get_prev_sibling(widget) will return @previous_child.
+ *
+ * If @parent is already set as the parent widget of @widget, this function can also be used
+ * to reorder @widget in the child widget list of @parent.
+ *
+ * Since: 3.92
+ */
+void
+gtk_widget_insert_after (GtkWidget *widget,
+ GtkWidget *parent,
+ GtkWidget *previous_sibling)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GTK_IS_WIDGET (parent));
+ g_return_if_fail (previous_sibling == NULL || GTK_IS_WIDGET (previous_sibling));
+ g_return_if_fail (previous_sibling == NULL || _gtk_widget_get_parent (previous_sibling) == parent);
+
+ if (widget == previous_sibling ||
+ (previous_sibling && _gtk_widget_get_prev_sibling (widget) == previous_sibling))
+ return;
+
+ if (!previous_sibling && _gtk_widget_get_first_child (parent) == widget)
+ return;
+
+ gtk_widget_reposition_after (widget,
+ parent,
+ previous_sibling);
+}
+
+/*
+ * @widget: a #GtkWidget
+ * @parent: the parent #GtkWidget to insert @widget into
+ * @next_child: (nullable): the new next sibling of @widget or %NULL
+ *
+ * Inserts @widget into the child widget list of @parent.
+ * It will be placed before @next_child, or at the end if @next_child is %NULL.
+ *
+ * After calling this function, gtk_widget_get_next_sibling(widget) will return @next_child
+ * if @next_child was not %NULL.
+ *
+ * If @parent is already set as the parent widget of @widget, this function can also be used
+ * to reorder @widget in the child widget list of @parent.
+ *
+ * Since: 3.92
+ */
+void
+gtk_widget_insert_before (GtkWidget *widget,
+ GtkWidget *parent,
+ GtkWidget *next_sibling)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GTK_IS_WIDGET (parent));
+ g_return_if_fail (next_sibling == NULL || GTK_IS_WIDGET (next_sibling));
+ g_return_if_fail (next_sibling == NULL || _gtk_widget_get_parent (next_sibling) == parent);
+
+ if (widget == next_sibling ||
+ (next_sibling && _gtk_widget_get_next_sibling (widget) == next_sibling))
+ return;
+
+ if (!next_sibling && _gtk_widget_get_last_child (parent) == widget)
+ return;
+
+ gtk_widget_reposition_after (widget, parent,
+ next_sibling ? _gtk_widget_get_prev_sibling (next_sibling) :
+ _gtk_widget_get_last_child (parent));
+}
+
void
gtk_widget_forall (GtkWidget *widget,
GtkCallback callback,
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index c1cbe2032a..9c3de471e9 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -1243,6 +1243,14 @@ GDK_AVAILABLE_IN_3_90
GtkWidget * gtk_widget_get_next_sibling (GtkWidget *widget);
GDK_AVAILABLE_IN_3_90
GtkWidget * gtk_widget_get_prev_sibling (GtkWidget *widget);
+GDK_AVAILABLE_IN_3_92
+void gtk_widget_insert_after (GtkWidget *widget,
+ GtkWidget *parent,
+ GtkWidget *previous_sibling);
+GDK_AVAILABLE_IN_3_92
+void gtk_widget_insert_before (GtkWidget *widget,
+ GtkWidget *parent,
+ GtkWidget *next_sibling);
GDK_AVAILABLE_IN_3_90
void gtk_widget_set_focus_child (GtkWidget *widget,
GtkWidget *child);